Compare commits

..

23 Commits

Author SHA1 Message Date
f1281858d3 feat: add output power manager 2025-07-09 22:44:23 +02:00
bdd6bae1a9 refactor: object to string method 2025-07-07 21:32:58 +02:00
b3d6ba9a54 bump to version 0.1.1 2025-07-07 20:58:52 +02:00
6828400a77 refactor code + add IDLE protocol listener 2025-07-07 20:54:28 +02:00
a0456516b5 refactor: cleanup include headers 2025-07-07 18:35:05 +02:00
d2ca1732f1 refactor: add shell version to command line option 2025-07-05 19:58:24 +02:00
2a88d12bfa refactor resource + add taskbar application switcher 2025-07-03 15:09:27 +02:00
363d0d1678 feat: add base layout for dashboard applcation list 2025-06-25 17:55:56 +02:00
be7a573bef refactor: allocated memeory should be in finalize method instead of dispose method 2025-06-24 17:52:35 +02:00
2775e497f5 Use default Gtk theme directory for shell theme + launch apps with the theme configured by the shell 2025-06-17 12:22:10 +02:00
12014a121d test: launch an application from the shell 2025-06-17 09:36:58 +02:00
8c70733b9b feat: add global keyboard handle to the session-shell, allow to show and hide dashboard via shortcut 2025-06-16 16:33:25 +02:00
1294edf250 refactor: define object properties names in header files 2025-06-16 13:40:25 +02:00
443f323597 refactor: define all signals to header files 2025-06-16 13:11:50 +02:00
7dab18e121 refactor: reorganize theme manager, allow set default theme + default virtual keyboard layout via envar 2025-06-16 11:47:51 +02:00
224252807a feat: add files monitor
FilesMonitor allows shell to monitor changes on a set of files.
This allows the shell to react in realtime any changes related
to its configurations such as: themes, keyboard, setting, etc.
2025-06-14 23:08:11 +02:00
e598847994 improve: using GtkRevealer to show/hide virtual keyboard in login shell 2025-06-14 15:23:14 +02:00
b10cfab3ba feat: implement the base classes for launcher + input
- Base classes for lancher: Dashboard + Taskbar
- Allow the shell to monitor directly wayland seat keyboard (on demand)
2025-06-13 19:34:12 +02:00
e6515cca06 feat: allow to set states on foreign windows: minimize maximize or full screen 2025-06-11 17:38:55 +02:00
3b22827e4f fix: unref css provider after remove it from style context 2025-03-21 10:31:01 +01:00
2c5338f4bf Virtual keyboard + configuration:
- complete implementation of virtual keyboard
- support loading user defined virtual keyboard from configuration at $XDG_CONFIG_HOME/xkb/
- support loading user defined CSS theme from $XDG_CONFIG_HOME/themes/
2025-03-21 10:04:08 +01:00
24f47dfd7f Load keyboard key caps from key map 2025-03-13 23:15:49 +01:00
8020954fed feat: add virtual keyboard ui 2025-03-13 00:54:14 +01:00
52 changed files with 6046 additions and 2045 deletions

View File

@ -1,3 +1,30 @@
# diya-shell # diya-shell
Wayland shell for diyac wayland compositor Wayland shell for diyac wayland compositor
# Environment variables
## Theme
Default theme can be set using the envar `DIYA_DEFAULT_THEME`, this will cause the shell searching for CSS file theme in
`/home/$USER/.themes/<name>/gtk-4.0/gtk.css`:
* diya-shell: will looking for file: `dev.iohub.diya.session-shell.css`
* diya-login-shell: will looking for file: `dev.iohub.diya.login-shell.css`
# Virtual keyboard layout
Default virtual keyboard keymap can be set via the `DIYA_VKB_KEYMAP` environment variable. When created virtual keyboard,
the shell will search for keymap file in: `/home/$USER/.config/diya/xkb/${DIYA_VKB_KEYMAP}.keymap`
# Launch terminal based application
create file in `/home/$USER/bin/xdg-terminal-exec` with:
```sh
#! /bin/sh
foot $@
```
this allows gtk4-launch to launch a terminal based application

View File

@ -1,6 +1,6 @@
project('diya-shell', project('diya-shell',
['c'], ['c'],
version: '0.1.0', version: '0.1.2',
license: 'MIT', license: 'MIT',
meson_version: '>=0.58.0', meson_version: '>=0.58.0',
default_options: ['c_std=gnu11', 'warning_level=3']) default_options: ['c_std=gnu11', 'warning_level=3'])
@ -12,6 +12,7 @@ add_project_arguments(
'-Wno-pedantic', '-Wno-pedantic',
'-Werror=implicit-function-declaration', '-Werror=implicit-function-declaration',
'-Werror=return-type', '-Werror=return-type',
'-D__SHELL_VERSION__="@0@"'.format(meson.project_version())
], ],
language: 'c') language: 'c')
@ -36,8 +37,10 @@ wayland_targets=[]
wl_protocols = [ wl_protocols = [
wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1', wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1',
wl_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1',
'protocols/wlr-foreign-toplevel-management-unstable-v1', 'protocols/wlr-foreign-toplevel-management-unstable-v1',
'protocols/virtual-keyboard-unstable-v1' 'protocols/virtual-keyboard-unstable-v1',
'protocols/wlr-output-power-management-unstable-v1',
] ]
foreach proto : wl_protocols foreach proto : wl_protocols
@ -52,11 +55,19 @@ endforeach
gnome=import('gnome') gnome=import('gnome')
incdir = include_directories([
'src'
])
base = [ base = [
'src/base.c', 'src/base.c',
'src/shell.c', 'src/shell.c',
'src/wayland.c', 'src/wayland.c',
'src/input.c',
'src/virtual-keyboard.c', 'src/virtual-keyboard.c',
'src/widgets/virtual-keyboard-widgets.c',
'src/files-monitor.c',
'src/idle.c',
wayland_targets wayland_targets
] ]
@ -67,17 +78,22 @@ dm_src = [
'src/session-shell.c', 'src/session-shell.c',
'src/foreign.c', 'src/foreign.c',
'src/session-lock.c', 'src/session-lock.c',
'src/session.c'] 'src/session.c',
'src/widgets/base-widgets.c',
'src/widgets/taskbar-widget.c',
'src/widgets/dashboard-widget.c',
]
buil_dep = [gtk, gtk_layer_shell, wayland_client, xkbcommon] buil_dep = [gtk, gtk_layer_shell, wayland_client, xkbcommon]
session_resource = gnome.compile_resources('session-resources','resources/session-shell/gresource.xml') session_resource = gnome.compile_resources('session-resources','resources/gresource-session.xml')
executable( executable(
'diya-shell', 'diya-shell',
dm_src, dm_src,
session_resource, session_resource,
dependencies: buil_dep) dependencies: buil_dep,
include_directories : incdir)
login_src = [ login_src = [
base, base,
@ -85,10 +101,11 @@ login_src = [
'src/login.c' 'src/login.c'
] ]
login_resource = gnome.compile_resources('login-resources','resources/login-shell/gresource.xml') login_resource = gnome.compile_resources('login-resources','resources/gresource-login.xml')
executable( executable(
'diya-login-shell', 'diya-login-shell',
login_src, login_src,
login_resource, login_resource,
dependencies: buil_dep) dependencies: buil_dep,
include_directories : incdir)

View File

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_output_power_management_unstable_v1">
<copyright>
Copyright © 2019 Purism SPC
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<description summary="Control power management modes of outputs">
This protocol allows clients to control power management modes
of outputs that are currently part of the compositor space. The
intent is to allow special clients like desktop shells to power
down outputs when the system is idle.
To modify outputs not currently part of the compositor space see
wlr-output-management.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible changes
may be added together with the corresponding interface version bump.
Backward incompatible changes are done by bumping the version number in
the protocol and interface names and resetting the interface version.
Once the protocol is to be declared stable, the 'z' prefix and the
version number in the protocol and interface names are removed and the
interface version number is reset.
</description>
<interface name="zwlr_output_power_manager_v1" version="1">
<description summary="manager to create per-output power management">
This interface is a manager that allows creating per-output power
management mode controls.
</description>
<request name="get_output_power">
<description summary="get a power management for an output">
Create an output power management mode control that can be used to
adjust the power management mode for a given output.
</description>
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
<arg name="output" type="object" interface="wl_output"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the manager">
All objects created by the manager will still remain valid, until their
appropriate destroy request has been called.
</description>
</request>
</interface>
<interface name="zwlr_output_power_v1" version="1">
<description summary="adjust power management mode for an output">
This object offers requests to set the power management mode of
an output.
</description>
<enum name="mode">
<entry name="off" value="0"
summary="Output is turned off."/>
<entry name="on" value="1"
summary="Output is turned on, no power saving"/>
</enum>
<enum name="error">
<entry name="invalid_mode" value="1" summary="nonexistent power save mode"/>
</enum>
<request name="set_mode">
<description summary="Set an outputs power save mode">
Set an output's power save mode to the given mode. The mode change
is effective immediately. If the output does not support the given
mode a failed event is sent.
</description>
<arg name="mode" type="uint" enum="mode" summary="the power save mode to set"/>
</request>
<event name="mode">
<description summary="Report a power management mode change">
Report the power management mode change of an output.
The mode event is sent after an output changed its power
management mode. The reason can be a client using set_mode or the
compositor deciding to change an output's mode.
This event is also sent immediately when the object is created
so the client is informed about the current power management mode.
</description>
<arg name="mode" type="uint" enum="mode"
summary="the output's new power management mode"/>
</event>
<event name="failed">
<description summary="object no longer valid">
This event indicates that the output power management mode control
is no longer valid. This can happen for a number of reasons,
including:
- The output doesn't support power management
- Another client already has exclusive power management mode control
for this output
- The output disappeared
Upon receiving this event, the client should destroy this object.
</description>
</event>
<request name="destroy" type="destructor">
<description summary="destroy this power management">
Destroys the output power management mode control object.
</description>
</request>
</interface>
</protocol>

View File

@ -0,0 +1,21 @@
@import url("resource:///dev/iohub/diya/shell/css/virtual-keyboard.css");
#diya_login_shell
{
}
#diya_login_shell label.diya-login-header {
font-size: 16px;
font-weight: bold;
}
#diya_login_shell label.diya-login-status {
font-size: 12px;
color: red;
}
#diya_login_shell button.diya-btn-show-vkb
{
color: gray;
min-width: 0px;
}

View File

@ -0,0 +1,21 @@
@import url("resource:///dev/iohub/diya/shell/css/virtual-keyboard.css");
diya-taskbar
{
background-color: orange;
}
diya-dashboard
{
background-color: lightgray;
}
#diya_shell_background
{
background-image:url("file:///etc/xdg/labwc/wpp.jpg");
background-size: cover;
}
flowbox flowboxchild {
border: 5px solid black;
}

View File

@ -0,0 +1,48 @@
diya-vkb
{
background-color: transparent;
/* border: 1px solid orangered; */
}
diya-vkb-button
{
background-color: white;
border: 1px solid #CDC7C2;
border-radius: 3px;
min-width: 30px;
min-height: 30px;
box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.19);
}
diya-vkb-button.active
{
background-color: #E7E6E2;
}
diya-vkb-button:hover
{
background-color: #E7E6E2;
}
/*
.diya-vkb-btn label {
border: 1px solid #b81f2b;
}*/
diya-vkb-button label.shift-level-1 {
color: black;
padding-top: 2px;
font-size: 12px;
}
diya-vkb-button label.shift-level-2 {
color: gray;
font-size: 9px;
padding-left: 3px;
}
diya-vkb-button label.shift-level-3 {
color: gray;
font-size: 9px;
padding-right: 3px;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/dev/iohub/diya/shell/css">
<file alias="dev.iohub.diya.login-shell.css">resources/css/login-shell.css</file>
<file alias="virtual-keyboard.css">resources/css/virtual-keyboard.css</file>
</gresource>
<gresource prefix="/dev/iohub/diya/shell/vkb">
<file alias="default.keymap">resources/vkb/default.keymap</file>
</gresource>
</gresources>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/dev/iohub/diya/shell/vkb">
<file alias="default.keymap">resources/vkb/default.keymap</file>
</gresource>
<gresource prefix="/dev/iohub/diya/shell/ui">
<file alias="dashboard.ui">resources/ui/dashboard.ui</file>
<file alias="taskbar.ui">resources/ui/taskbar.ui</file>
</gresource>
<gresource prefix="/dev/iohub/diya/shell/css">
<file alias="dev.iohub.diya.session-shell.css">resources/css/session-shell.css</file>
<file alias="virtual-keyboard.css">resources/css/virtual-keyboard.css</file>
</gresource>
<gresource prefix="/dev/iohub/diya/shell/icons/scalable">
<file alias="gear">resources/icons/scalable/gear.svg</file>
</gresource>
</gresources>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><linearGradient id="L4rKfs~Qrm~k0Pk8MRsoza" x1="32.012" x2="15.881" y1="32.012" y2="15.881" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".242" stop-color="#f2f2f2"/><stop offset="1" stop-color="#ccc"/></linearGradient><circle cx="24" cy="24" r="11.5" fill="url(#L4rKfs~Qrm~k0Pk8MRsoza)"/><linearGradient id="L4rKfs~Qrm~k0Pk8MRsozb" x1="17.45" x2="28.94" y1="17.45" y2="28.94" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0d61a9"/><stop offset=".363" stop-color="#0e5fa4"/><stop offset=".78" stop-color="#135796"/><stop offset="1" stop-color="#16528c"/></linearGradient><circle cx="24" cy="24" r="7" fill="url(#L4rKfs~Qrm~k0Pk8MRsozb)"/><linearGradient id="L4rKfs~Qrm~k0Pk8MRsozc" x1="5.326" x2="38.082" y1="5.344" y2="38.099" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#889097"/><stop offset=".331" stop-color="#848c94"/><stop offset=".669" stop-color="#78828b"/><stop offset="1" stop-color="#64717c"/></linearGradient><path fill="url(#L4rKfs~Qrm~k0Pk8MRsozc)" d="M43.407,19.243c-2.389-0.029-4.702-1.274-5.983-3.493c-1.233-2.136-1.208-4.649-0.162-6.693 c-2.125-1.887-4.642-3.339-7.43-4.188C28.577,6.756,26.435,8,24,8s-4.577-1.244-5.831-3.131c-2.788,0.849-5.305,2.301-7.43,4.188 c1.046,2.044,1.071,4.557-0.162,6.693c-1.281,2.219-3.594,3.464-5.983,3.493C4.22,20.77,4,22.358,4,24 c0,1.284,0.133,2.535,0.364,3.752c2.469-0.051,4.891,1.208,6.213,3.498c1.368,2.37,1.187,5.204-0.22,7.345 c2.082,1.947,4.573,3.456,7.34,4.375C18.827,40.624,21.221,39,24,39s5.173,1.624,6.303,3.971c2.767-0.919,5.258-2.428,7.34-4.375 c-1.407-2.141-1.588-4.975-0.22-7.345c1.322-2.29,3.743-3.549,6.213-3.498C43.867,26.535,44,25.284,44,24 C44,22.358,43.78,20.77,43.407,19.243z M24,34.5c-5.799,0-10.5-4.701-10.5-10.5c0-5.799,4.701-10.5,10.5-10.5S34.5,18.201,34.5,24 C34.5,29.799,29.799,34.5,24,34.5z"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/dev/iohub/diya/shell">
<file alias="login-shell.css">resources/login-shell/login-shell.css</file>
<file alias="default.keymap">resources/default.keymap</file>
</gresource>
</gresources>

View File

@ -1,9 +0,0 @@
.header {
font-size: 16px;
font-weight: bold;
}
.status {
font-size: 12px;
color: red;
}

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/dev/iohub/diya/shell">
<file alias="default.keymap">resources/default.keymap</file>
</gresource>
</gresources>

94
resources/ui/dashboard.ui Normal file
View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="DiyaDashboardWidget" parent="DiyaShellWindow">
<!--property name="title" translatable="yes">Example Application</property-->
<!--property name="default-width">600</property>
<property name="default-height">400</property-->
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkRevealer" id="revealer">
<property name="transition-type">slide-up</property>
<property name="reveal-child">0</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="header">
<property name="orientation">horizontal</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="hexpand">1</property>
<signal name="search-changed" handler="diya_dashboard_search_text_changed"/>
</object>
</child>
<child>
<object class="GtkMenuButton" id="gears">
<property name="direction">none</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="vexpand">1</property>
<property name="hexpand">1</property>
<child>
<object class="GtkStackPage">
<property name="name">app_list</property>
<property name="title">Application list</property>
<property name="child">
<object class="GtkScrolledWindow" id="sidebar-sw">
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkFlowBox" id="app_list_box">
<property name="activate-on-single-click">1</property>
<signal name="child-activated" handler="diya_dashboard_app_launch"/>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">search_list</property>
<property name="title">Search</property>
<property name="child">
<object class="GtkLabel">
<property name="label">second stack child</property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
</object>
</child>
<!--child>
<object class="GtkBox" id="taskbar">
<property name="orientation">horizontal</property>
<child>
<object class="GtkButton" id="btn_launch">
<property name="visible">1</property>
<property name="label" translatable="yes">Terminal</property>
<signal name="clicked" handler="diya_dashboard_launch"/>
</object>
</child>
</object>
</child-->
</object>
</child>
</template>
</interface>

34
resources/ui/taskbar.ui Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="DiyaTaskbarWidget" parent="DiyaShellWindow">
<!--property name="title" translatable="yes">Example Application</property-->
<!--property name="default-width">600</property>
<property name="default-height">400</property-->
<child>
<object class="GtkBox" id="taskbar">
<property name="hexpand">1</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkToggleButton" id="btn_toggle">
<property name="visible">1</property>
<property name="label" translatable="yes">Diya</property>
<!--signal name="toggled" handler="diya_dashboard_toggle"/-->
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vscrollbar-policy">never</property>
<child>
<object class="GtkListView" id="apps_list">
<property name="orientation">horizontal</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

1910
resources/vkb/default.keymap Normal file

File diff suppressed because it is too large Load Diff

7
resources/vkb/tpl.keymap Normal file
View File

@ -0,0 +1,7 @@
xkb_keymap {
xkb_keycodes { include "evdev+aliases(azerty)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_symbols { include "pc+fr+inet(evdev)" };
xkb_geometry { include "pc(pc105)" };
};

View File

@ -1,6 +1,7 @@
#include "background.h" #include "background.h"
#include "session-shell.h"
#include <assert.h> #include <assert.h>
#define NAMESPACE "background" #define NAMESPACE "diya_shell_background"
static void on_background_destroy(GtkWindow *window, GApplication *_data) static void on_background_destroy(GtkWindow *window, GApplication *_data)
{ {
@ -12,7 +13,7 @@ static void on_background_destroy(GtkWindow *window, GApplication *_data)
void diya_session_shell_init_background(DiyaSessionShell * shell) void diya_session_shell_init_background(DiyaSessionShell * shell)
{ {
GtkApplication * app; GtkApplication * app;
g_object_get(shell, "application", &app, NULL); g_object_get(shell, DIYA_PROP_SHELL_APPLICATION, &app, NULL);
assert(app); assert(app);
GtkWindow *gtk_window = GTK_WINDOW (gtk_application_window_new (app)); GtkWindow *gtk_window = GTK_WINDOW (gtk_application_window_new (app));
assert(gtk_window); assert(gtk_window);

View File

@ -1,7 +1,8 @@
#ifndef DIYA_SHELL_BACKGROUND_H #ifndef DIYA_SHELL_BACKGROUND_H
#define DIYA_SHELL_BACKGROUND_H #define DIYA_SHELL_BACKGROUND_H
#include "session-shell.h" #include "base.h"
USE_CLASS(DiyaSessionShell);
void diya_session_shell_init_background(DiyaSessionShell * shell); void diya_session_shell_init_background(DiyaSessionShell * shell);

View File

@ -3,6 +3,11 @@
G_DEFINE_ABSTRACT_TYPE(DiyaObject, diya_object, G_TYPE_OBJECT) G_DEFINE_ABSTRACT_TYPE(DiyaObject, diya_object, G_TYPE_OBJECT)
static void diya_object_finalize(GObject* object)
{
g_debug("diya_object_finalize: %s", diya_object_to_string(object));
G_OBJECT_CLASS (diya_object_parent_class)->finalize(object);
}
static void diya_object_dispose(GObject* object) static void diya_object_dispose(GObject* object)
{ {
@ -15,6 +20,7 @@ static void diya_object_class_init(DiyaObjectClass *class)
GObjectClass *gobject_class = G_OBJECT_CLASS(class); GObjectClass *gobject_class = G_OBJECT_CLASS(class);
class->to_string = NULL; class->to_string = NULL;
gobject_class->dispose = diya_object_dispose; gobject_class->dispose = diya_object_dispose;
gobject_class->finalize = diya_object_finalize;
} }
static void diya_object_init(DiyaObject *self) static void diya_object_init(DiyaObject *self)
@ -22,6 +28,11 @@ static void diya_object_init(DiyaObject *self)
(void) self; (void) self;
} }
/**
* @brief Implementation of DiyaShellObject
*
*/
enum enum
{ {
SO_NO_PROP, SO_NO_PROP,
@ -38,6 +49,12 @@ typedef struct _DiyaShellObjectPrivate
} DiyaShellObjectPrivate; } DiyaShellObjectPrivate;
G_DEFINE_TYPE_WITH_PRIVATE(DiyaShellObject, diya_shell_object, DIYA_TYPE_OBJECT); G_DEFINE_TYPE_WITH_PRIVATE(DiyaShellObject, diya_shell_object, DIYA_TYPE_OBJECT);
static void diya_shell_object_finalize(GObject* object)
{
g_debug("diya_shell_object_finalize: %s", diya_object_to_string(object));
G_OBJECT_CLASS(diya_shell_object_parent_class)->finalize(object);
}
static void diya_shell_object_dispose(GObject* object) static void diya_shell_object_dispose(GObject* object)
{ {
g_debug("diya_shell_object_dispose: %s", diya_object_to_string(object)); g_debug("diya_shell_object_dispose: %s", diya_object_to_string(object));
@ -86,9 +103,10 @@ static void diya_shell_object_class_init(DiyaShellObjectClass *class)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS(class); GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_shell_object_dispose; gobject_class->dispose = diya_shell_object_dispose;
gobject_class->finalize = diya_shell_object_finalize;
gobject_class->set_property = diya_shell_object_set_property; gobject_class->set_property = diya_shell_object_set_property;
gobject_class->get_property = diya_shell_object_get_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_so_prop[SO_SHELL] = g_param_spec_pointer(DIYA_PROP_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); g_object_class_install_properties (gobject_class, SO_N_PROPERTIES, g_so_prop);
} }
@ -101,3 +119,10 @@ const gchar * diya_object_to_string(gpointer object)
DiyaObjectClass *class = DIYA_OBJECT_GET_CLASS(self); DiyaObjectClass *class = DIYA_OBJECT_GET_CLASS(self);
return class->to_string ? class->to_string(self) : ""; return class->to_string ? class->to_string(self) : "";
} }
gpointer diya_shell_object_get_shell(gpointer object)
{
DiyaShellObject * self = DIYA_SHELL_OBJECT(object);
DiyaShellObjectPrivate* priv = diya_shell_object_get_instance_private(self);
return priv->shell;
}

View File

@ -3,6 +3,11 @@
#include <glib-object.h> #include <glib-object.h>
#include <assert.h> #include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#define USE_CLASS(name) typedef struct _##name name
#define DIYA_PROP_SHELL "shell"
/** /**
* Base class object * Base class object
@ -30,5 +35,6 @@ struct _DiyaShellObjectClass
}; };
const gchar *diya_object_to_string(gpointer object); const gchar *diya_object_to_string(gpointer object);
gpointer diya_shell_object_get_shell(gpointer object);
#endif #endif

14
src/files-monior.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef DIYA_FILES_MONITOR_H
#define DIYA_FILES_MONITOR_H
#include "base.h"
#define DIYA_TYPE_FILES_MONITOR (diya_files_monitor_get_type ())
G_DECLARE_FINAL_TYPE (DiyaFilesMonitor, diya_files_monitor, DIYA, FILES_MONITOR, DiyaObject)
DiyaFilesMonitor* diya_files_monitor_new();
gboolean diya_files_monitor_watch(DiyaFilesMonitor* monitor, const gchar* file, GCallback callback, gpointer userdata);
void diya_files_monitor_unwatch(DiyaFilesMonitor* monitor, const gchar* file);
#endif

91
src/files-monitor.c Normal file
View File

@ -0,0 +1,91 @@
#include <glib-unix.h>
#include <gio/gio.h>
#include <stdbool.h>
#include "files-monior.h"
struct _DiyaFilesMonitor
{
DiyaObject parent;
GHashTable *watch_table;
};
G_DEFINE_FINAL_TYPE(DiyaFilesMonitor, diya_files_monitor, DIYA_TYPE_OBJECT)
static void diya_files_monitor_finalize(GObject *object)
{
DiyaFilesMonitor *self = DIYA_FILES_MONITOR(object);
g_debug("diya_files_monitor_finalize: %s", diya_object_to_string(object));
g_hash_table_destroy(self->watch_table);
G_OBJECT_CLASS(diya_files_monitor_parent_class)->finalize(object);
}
static void diya_files_monitor_dispose(GObject *object)
{
// DiyaFilesMonitor *self = DIYA_FILES_MONITOR(object);
g_debug("diya_files_monitor_dispose: %s", diya_object_to_string(object));
G_OBJECT_CLASS(diya_files_monitor_parent_class)->dispose(object);
}
static void diya_files_monitor_init(DiyaFilesMonitor *self)
{
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
}
static const gchar *diya_files_monitor_to_string(DiyaObject *object)
{
(void) object;
return "Diya Files Monitor";
}
static void diya_files_monitor_class_init(DiyaFilesMonitorClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->finalize = diya_files_monitor_finalize;
gobject_class->dispose = diya_files_monitor_dispose;
base_class->to_string = diya_files_monitor_to_string;
}
DiyaFilesMonitor* diya_files_monitor_new()
{
DiyaFilesMonitor* self = DIYA_FILES_MONITOR(g_object_new(DIYA_TYPE_FILES_MONITOR, NULL));
return self;
}
gboolean diya_files_monitor_watch(DiyaFilesMonitor* self, const gchar* path, GCallback callback, gpointer userdata)
{
GFileMonitor* fm = NULL;
if(!g_hash_table_contains(self->watch_table, path))
{
GError *err = NULL;
GFile* file = g_file_new_for_path(path);
fm = g_file_monitor(file, G_FILE_MONITOR_WATCH_MOVES, NULL, &err);
g_object_unref(file);
if (err)
{
g_warning("Unable to watch file %s: %s", path, err->message);
g_error_free(err);
return false;
}
g_info("DiyaFilesMonitor: watch new file: %s", path);
g_hash_table_insert(self->watch_table, (gpointer)g_strdup(path), fm);
}
else
{
g_info("File %s is already watched, register callback handle to the existing watcher", path);
fm = g_hash_table_lookup(self->watch_table, path);
}
g_signal_connect(G_OBJECT(fm), "changed", callback, userdata);
return true;
}
void diya_files_monitor_unwatch(DiyaFilesMonitor* self, const gchar* path)
{
if(!g_hash_table_contains(self->watch_table, path))
{
g_hash_table_remove(self->watch_table, (gconstpointer)path);
}
}

View File

@ -2,6 +2,8 @@
#include <inttypes.h> #include <inttypes.h>
#include "wlr-foreign-toplevel-management-unstable-v1.h" #include "wlr-foreign-toplevel-management-unstable-v1.h"
#include "foreign.h" #include "foreign.h"
#include "wayland.h"
#include "session-shell.h"
/** /**
* @DiyaForeignWindow Object definition * @DiyaForeignWindow Object definition
@ -26,22 +28,36 @@ struct _DiyaForeignWindow
gchar* title; gchar* title;
enum diya_win_state state; enum diya_win_state state;
DiyaForeignWindow * parent_win; DiyaForeignWindow * parent_win;
gchar string[128]; gchar* string;
}; };
G_DEFINE_FINAL_TYPE(DiyaForeignWindow, diya_foreign_window, DIYA_TYPE_SHELL_OBJECT) G_DEFINE_FINAL_TYPE(DiyaForeignWindow, diya_foreign_window, DIYA_TYPE_SHELL_OBJECT)
static void diya_foreign_window_finalize(GObject* object)
{
DiyaForeignWindow * self = DIYA_FOREIGN_WINDOW(object);
g_debug("diya_foreign_window_finalize: %s", diya_object_to_string(self));
if(self->appid)
{
g_free(self->appid);
self->appid = NULL;
}
if(self->title)
{
g_free(self->title);
self->title = NULL;
}
if(self->string)
{
g_free(self->string);
self->string = NULL;
}
G_OBJECT_CLASS(diya_foreign_window_parent_class)->finalize(object);
}
static void diya_foreign_window_dispose(GObject* object) static void diya_foreign_window_dispose(GObject* object)
{ {
DiyaForeignWindow * self = DIYA_FOREIGN_WINDOW(object); DiyaForeignWindow * self = DIYA_FOREIGN_WINDOW(object);
g_debug("diya_foreign_window_dispose: %s", diya_object_to_string(self)); g_debug("diya_foreign_window_dispose: %s", diya_object_to_string(self));
if(self->appid)
{
g_free(self->appid);
}
if(self->title)
{
g_free(self->title);
}
G_OBJECT_CLASS(diya_foreign_window_parent_class)->dispose(object); G_OBJECT_CLASS(diya_foreign_window_parent_class)->dispose(object);
} }
@ -114,13 +130,18 @@ static void diya_foreign_window_init(DiyaForeignWindow *self)
//self->shell = NULL; //self->shell = NULL;
self->state = DIYA_WIN_STATE_NONE; self->state = DIYA_WIN_STATE_NONE;
self->title = NULL; self->title = NULL;
memset(self->string, 0, sizeof(self->string)); self->string = NULL;
} }
static const gchar* diya_foreign_window_to_string(DiyaObject* object) static const gchar* diya_foreign_window_to_string(DiyaObject* object)
{ {
DiyaForeignWindow* self = DIYA_FOREIGN_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:""); if(!self->string)
{
self->string = (char*) malloc(128);
g_snprintf(self->string, 128, "Window 0x%" PRIXPTR ": %s (%s)", (uintptr_t) self->handle, self->appid?self->appid:"", self->title?self->title:"");
}
return self->string; return self->string;
} }
@ -130,20 +151,19 @@ static void diya_foreign_window_class_init(DiyaForeignWindowClass *class)
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class); DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_foreign_window_dispose; gobject_class->dispose = diya_foreign_window_dispose;
gobject_class->finalize = diya_foreign_window_finalize;
gobject_class->set_property = diya_foreign_window_set_property; gobject_class->set_property = diya_foreign_window_set_property;
gobject_class->get_property = diya_foreign_window_get_property; gobject_class->get_property = diya_foreign_window_get_property;
base_class->to_string = diya_foreign_window_to_string; 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_APP_ID] = g_param_spec_string(DIYA_PROP_FOREIGN_WINDOW_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_TITLE] = g_param_spec_string(DIYA_PROP_FOREIGN_WINDOW_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_HANDLE] = g_param_spec_pointer(DIYA_PROP_FOREIGN_WINDOW_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_STATE] = g_param_spec_uint(DIYA_PROP_FOREIGN_WINDOW_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[WIN_PARENT] = g_param_spec_pointer(DIYA_PROP_FOREIGN_WINDOW_PARENT, NULL, "Window parent", G_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, N_PROPERTIES, win_properties); 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, static void toplevel_handle_output_leave(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle, struct zwlr_foreign_toplevel_handle_v1 *handle,
struct wl_output *output) struct wl_output *output)
@ -173,6 +193,7 @@ static void toplevel_handle_app_id(void *data,
assert(win); assert(win);
g_object_set(win, "appid", app_id, NULL); g_object_set(win, "appid", app_id, NULL);
g_debug("New appid for: %s", diya_object_to_string(win)); g_debug("New appid for: %s", diya_object_to_string(win));
g_signal_emit_by_name(shell, DIYA_SIGNAL_FOREIGN_WINDOW_ADDED, (void *)win);
} }
static void toplevel_handle_output_enter(void *data, static void toplevel_handle_output_enter(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle, struct zwlr_foreign_toplevel_handle_v1 *handle,
@ -207,7 +228,10 @@ static void toplevel_handle_state(void *data,
wstate |= DIYA_WIN_STATE_FOCUS; wstate |= DIYA_WIN_STATE_FOCUS;
break; break;
} }
g_debug("toplevel_handle_state %s: (%.04x) active: %d, full screen %d, maximize %d, minimize %d", diya_object_to_string(win), wstate, wstate & DIYA_WIN_STATE_FOCUS,
wstate & DIYA_WIN_STATE_FULLSCREEN, wstate & DIYA_WIN_STATE_MAXIMIZE, wstate & DIYA_WIN_STATE_MINIMIZE);
g_object_set(win, "state", wstate, NULL); g_object_set(win, "state", wstate, NULL);
g_signal_emit_by_name(shell, DIYA_SIGNAL_FOREIGN_WINDOW_STATE_CHANGED, (void *)win, (guint)wstate);
} }
static void toplevel_handle_done(void *data, static void toplevel_handle_done(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle) struct zwlr_foreign_toplevel_handle_v1 *handle)
@ -216,7 +240,8 @@ static void toplevel_handle_done(void *data,
assert(shell); assert(shell);
DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle); DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle);
assert(win); assert(win);
g_signal_emit_by_name(shell, "foreign-window-changed", (void *)win); g_debug("toplevel_handle_done: finish");
g_signal_emit_by_name(shell, DIYA_SIGNAL_FOREIGN_WINDOW_CHANGED, (void *)win);
} }
static void toplevel_handle_closed(void *data, static void toplevel_handle_closed(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle) struct zwlr_foreign_toplevel_handle_v1 *handle)
@ -225,7 +250,7 @@ static void toplevel_handle_closed(void *data,
assert(shell); assert(shell);
DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle); DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle);
assert(win); assert(win);
g_signal_emit_by_name(shell, "foreign-window-removed", (void *)win); g_signal_emit_by_name(shell, DIYA_SIGNAL_FOREIGN_WINDOW_REMOVED, (void *)win);
diya_session_shell_remove_window(shell, win); diya_session_shell_remove_window(shell, win);
zwlr_foreign_toplevel_handle_v1_destroy(handle); zwlr_foreign_toplevel_handle_v1_destroy(handle);
} }
@ -302,9 +327,114 @@ static const struct zwlr_foreign_toplevel_manager_v1_listener g_toplevel_manager
.finished = toplevel_manager_handle_finished, .finished = toplevel_manager_handle_finished,
}; };
void diya_session_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell) void diya_session_shell_foreign_toplevel_register(gpointer mngr, DiyaShell *shell)
{ {
DiyaSessionShell* session_shell = DIYA_SESSION_SHELL(shell); DiyaSessionShell* session_shell = DIYA_SESSION_SHELL(shell);
g_toplevel_manager = wl_registry_bind(registry, name, &zwlr_foreign_toplevel_manager_v1_interface, 3); zwlr_foreign_toplevel_manager_v1_add_listener(mngr, &g_toplevel_manager_impl, (void *)session_shell);
zwlr_foreign_toplevel_manager_v1_add_listener(g_toplevel_manager, &g_toplevel_manager_impl, (void *)session_shell); }
DiyaShell* diya_foreign_window_get_shell(DiyaForeignWindow* self)
{
assert(self);
gpointer ptr;
g_object_get(self, DIYA_PROP_SHELL, &ptr, NULL);
DiyaShell* shell = DIYA_SHELL(ptr);
assert(shell);
return shell;
}
void diya_foreign_window_set_state(DiyaForeignWindow* self, enum diya_win_state state, bool value)
{
DiyaShell* shell = diya_foreign_window_get_shell(self);
DiyaWayland* wl = diya_shell_get_wayland(shell);
assert(wl);
if(state & DIYA_WIN_STATE_MINIMIZE)
{
if(value)
{
zwlr_foreign_toplevel_handle_v1_set_minimized(self->handle);
}
else
{
zwlr_foreign_toplevel_handle_v1_unset_minimized(self->handle);
}
}
if(state & DIYA_WIN_STATE_MAXIMIZE)
{
if(value)
{
zwlr_foreign_toplevel_handle_v1_set_maximized(self->handle);
}
else
{
zwlr_foreign_toplevel_handle_v1_unset_maximized(self->handle);
}
}
if(state & DIYA_WIN_STATE_FULLSCREEN)
{
struct wl_output* output = diya_wayland_get_output(wl, 0);
if(value)
{
zwlr_foreign_toplevel_handle_v1_set_fullscreen(self->handle, output);
}
else
{
zwlr_foreign_toplevel_handle_v1_unset_fullscreen(self->handle);
}
}
if(state & DIYA_WIN_STATE_FOCUS)
{
if(value)
{
struct wl_seat* seat = diya_wayland_get_seat(wl);
zwlr_foreign_toplevel_handle_v1_activate(self->handle, seat);
}
}
}
bool diya_foreign_window_is_toplevel(DiyaForeignWindow* self)
{
return self->parent_win == NULL;
}
static gint app_info_str_cmp(GAppInfo* info, const char* id)
{
return g_strcmp0(g_app_info_get_executable(info), id);
}
GAppInfo* diya_foreign_window_get_app_info(DiyaForeignWindow* self)
{
if(! self->appid)
{
return NULL;
}
GList* apps = g_app_info_get_all();
GList* found = g_list_find_custom(apps, self->appid, (GCompareFunc)app_info_str_cmp);
GAppInfo* info = NULL;
if(found && found->data)
{
assert(G_IS_APP_INFO(found->data));
info = g_object_ref(found->data);
}
g_list_free_full(apps, g_object_unref);
return info;
}
enum diya_win_state diya_foreign_window_get_state(DiyaForeignWindow* window)
{
return window->state;
}
DiyaForeignWindow* diya_foreign_window_get_top_level(DiyaForeignWindow* self)
{
DiyaForeignWindow* win = self;
while(win->parent_win)
{
win = win->parent_win;
}
return win;
} }

View File

@ -1,6 +1,16 @@
#ifndef DIYA_SHELL_FOREIGN_H #ifndef DIYA_SHELL_FOREIGN_H
#define DIYA_SHELL_FOREIGN_H #define DIYA_SHELL_FOREIGN_H
#include "session-shell.h" #include "base.h"
#define DIYA_TYPE_FOREIGN_WINDOW (diya_foreign_window_get_type ())
G_DECLARE_FINAL_TYPE (DiyaForeignWindow, diya_foreign_window, DIYA, FOREIGN_WINDOW, DiyaShellObject)
#define DIYA_PROP_FOREIGN_WINDOW_APPID "appid"
#define DIYA_PROP_FOREIGN_WINDOW_TITLE "title"
#define DIYA_PROP_FOREIGN_WINDOW_HANDLE "handle"
#define DIYA_PROP_FOREIGN_WINDOW_STATE "state"
#define DIYA_PROP_FOREIGN_WINDOW_PARENT "parent"
enum diya_win_state enum diya_win_state
{ {
@ -11,6 +21,16 @@ enum diya_win_state
DIYA_WIN_STATE_FOCUS = 1 << 3, DIYA_WIN_STATE_FOCUS = 1 << 3,
}; };
void diya_session_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t name, DiyaShell * shell); USE_CLASS(DiyaShell);
USE_CLASS(GAppInfo);
void diya_session_shell_foreign_toplevel_register(gpointer mngr, DiyaShell * shell);
DiyaShell* diya_foreign_window_get_shell(DiyaForeignWindow* window);
void diya_foreign_window_set_state(DiyaForeignWindow* window, enum diya_win_state state, bool value);
enum diya_win_state diya_foreign_window_get_state(DiyaForeignWindow* window);
bool diya_foreign_window_is_toplevel(DiyaForeignWindow* window);
DiyaForeignWindow* diya_foreign_window_get_top_level(DiyaForeignWindow* window);
GAppInfo* diya_foreign_window_get_app_info(DiyaForeignWindow* window);
#endif #endif

135
src/idle.c Normal file
View File

@ -0,0 +1,135 @@
#include "idle.h"
#include "wayland.h"
#include "ext-idle-notify-v1.h"
#include "shell.h"
struct _DiyaIdleNotification
{
DiyaShellObject parent;
struct ext_idle_notification_v1* notification;
guint timeout;
gchar* str;
};
G_DEFINE_FINAL_TYPE(DiyaIdleNotification, diya_idle_notification, DIYA_TYPE_SHELL_OBJECT)
static void diya_idle_notification_finalize(GObject* object)
{
(void) object;
DiyaIdleNotification * self = DIYA_IDLE_NOTIFICATION(object);
if(self->notification)
{
ext_idle_notification_v1_destroy(self->notification);
self->notification = NULL;
}
g_debug("diya_idle_notification_finalize: %s", diya_object_to_string(object));
if(self->str)
{
g_free(self->str);
self->str = NULL;
}
G_OBJECT_CLASS(diya_idle_notification_parent_class)->finalize(object);
}
static void diya_idle_notification_dispose(GObject* object)
{
(void) object;
// DiyaIdleNotification * self = DIYA_IDLE_NOTIFICATION(object);
g_debug("diya_idle_notification_dispose: %s", diya_object_to_string(object));
G_OBJECT_CLASS(diya_idle_notification_parent_class)->dispose(object);
}
static void diya_idle_notification_init(DiyaIdleNotification * self)
{
self->notification = NULL;
self->str = NULL;
}
static const gchar* diya_idle_notification_to_string(DiyaObject* object)
{
DiyaIdleNotification * self = DIYA_IDLE_NOTIFICATION(object);
if(!self->str)
{
self->str = (gchar*) malloc(64);
g_snprintf(self->str, 64, "DiyaIdleNotification for timeout: %d (ms)", self->timeout);
}
return self->str;
}
static void diya_idle_notification_class_init(DiyaIdleNotificationClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_idle_notification_dispose;
gobject_class->finalize = diya_idle_notification_finalize;
base_class->to_string = diya_idle_notification_to_string;
g_signal_new(DIYA_SIGNAL_IDLE_NOTIF_IDLE,
DIYA_TYPE_IDLE_NOTIFICATION,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
g_signal_new(DIYA_SIGNAL_IDLE_NOTIF_RESUME,
DIYA_TYPE_IDLE_NOTIFICATION,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
}
void diya_idle(void *data, struct ext_idle_notification_v1 *notification)
{
(void) notification;
DiyaIdleNotification* self = data;
g_signal_emit_by_name(self, DIYA_SIGNAL_IDLE_NOTIF_IDLE);
}
void diya_resume(void *data, struct ext_idle_notification_v1 *notification)
{
(void) notification;
DiyaIdleNotification* self = data;
g_signal_emit_by_name(self, DIYA_SIGNAL_IDLE_NOTIF_RESUME);
}
static const struct ext_idle_notification_v1_listener g_idle_listener_impl =
{
.idled = diya_idle,
.resumed = diya_resume
};
DiyaIdleNotification* diya_shell_get_idle_notification(DiyaShell* shell, guint timeout_ms)
{
DiyaWayland *wayland = diya_shell_get_wayland(shell);
struct ext_idle_notifier_v1* mngr = diya_wayland_get_idle_mngr(wayland);
if(!mngr)
{
return NULL;
}
DiyaIdleNotification* self = g_object_new(DIYA_TYPE_IDLE_NOTIFICATION, "shell", shell, NULL);
struct wl_seat *seat = diya_wayland_get_seat(wayland);
self->timeout = timeout_ms;
self->notification = ext_idle_notifier_v1_get_idle_notification(mngr, timeout_ms, seat);
ext_idle_notification_v1_add_listener(self->notification, &g_idle_listener_impl, self);
return self;
}
guint diya_idle_notification_get_timeout(DiyaIdleNotification* self)
{
return self->timeout;
}

17
src/idle.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef DIYAC_IDLE_H
#define DIYAC_IDLE_H
#include "base.h"
#define DIYA_SIGNAL_IDLE_NOTIF_IDLE "idle"
#define DIYA_SIGNAL_IDLE_NOTIF_RESUME "resume"
#define DIYA_TYPE_IDLE_NOTIFICATION (diya_idle_notification_get_type ())
G_DECLARE_FINAL_TYPE (DiyaIdleNotification, diya_idle_notification, DIYA, IDLE_NOTIFICATION, DiyaShellObject)
USE_CLASS(DiyaShell);
void diya_idle_manager_register(gpointer mngr, DiyaShell *shell);
DiyaIdleNotification* diya_shell_get_idle_notification(DiyaShell* shell, guint timeout_ms);
guint diya_idle_notification_get_timeout(DiyaIdleNotification* self);
#endif /* DIYAC_IDLE_H */

243
src/input.c Normal file
View File

@ -0,0 +1,243 @@
#include "input.h"
#include <wayland-client-protocol.h>
#include <gdk/wayland/gdkwayland.h>
#include <assert.h>
#include <xkbcommon/xkbcommon.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <gio/gio.h>
#include "wlr-foreign-toplevel-management-unstable-v1.h"
#include "virtual-keyboard-unstable-v1.h"
#include "wayland.h"
#include "shell.h"
struct _DiyaInput
{
DiyaShellObject parent;
gchar *name;
struct wl_keyboard *keyboard;
struct wl_seat *seat;
struct xkb_state *xkb_state;
struct xkb_context *xkb_context;
struct xkb_keymap *xkb_keymap;
};
G_DEFINE_FINAL_TYPE(DiyaInput, diya_input, DIYA_TYPE_SHELL_OBJECT)
static void diya_input_finalize(GObject *object)
{
g_debug("diya_input_finalize: %s", diya_object_to_string(object));
DiyaInput *self = DIYA_INPUT(object);
if (self->name)
{
g_free(self->name);
self->name = NULL;
}
if (self->keyboard)
{
wl_keyboard_release(self->keyboard);
self->keyboard = NULL;
}
G_OBJECT_CLASS(diya_input_parent_class)->finalize(object);
}
static void diya_input_dispose(GObject *object)
{
g_debug("diya_input_dispose: %s", diya_object_to_string(object));
DiyaInput *self = DIYA_INPUT(object);
if (self->xkb_keymap)
{
xkb_keymap_unref(self->xkb_keymap);
self->xkb_keymap = NULL;
}
if (self->xkb_state)
{
xkb_state_unref(self->xkb_state);
self->xkb_state = NULL;
}
if (self->xkb_context)
{
xkb_context_unref(self->xkb_context);
self->xkb_context = NULL;
}
G_OBJECT_CLASS(diya_input_parent_class)->dispose(object);
}
static void diya_input_init(DiyaInput *self)
{
self->name = NULL;
self->keyboard = NULL;
self->xkb_state = NULL;
self->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
self->xkb_keymap = NULL;
}
static const gchar *diya_input_to_string(DiyaObject *object)
{
DiyaInput *self = DIYA_INPUT(object);
if (self->name)
{
return self->name;
}
return "unknown";
}
static void diya_input_class_init(DiyaInputClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_input_dispose;
gobject_class->finalize = diya_input_finalize;
// gobject_class->set_property = diya_input_set_property;
// gobject_class->get_property = diya_input_get_property;
base_class->to_string = diya_input_to_string;
}
static void wl_keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size)
{
(void)keyboard;
DiyaInput *self = data;
assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
assert(map_shm != MAP_FAILED);
struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_string(self->xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
munmap(map_shm, size);
close(fd);
struct xkb_state *xkb_state = xkb_state_new(xkb_keymap);
xkb_keymap_unref(self->xkb_keymap);
xkb_state_unref(self->xkb_state);
self->xkb_keymap = xkb_keymap;
self->xkb_state = xkb_state;
}
static void wl_keyboard_enter(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface,
struct wl_array *keys)
{
(void)keyboard;
(void)serial;
(void)surface;
DiyaInput *self = data;
GList* keys_list = NULL;
uint32_t *key;
wl_array_for_each(key, keys)
{
keys_list = g_list_append(keys_list, (gpointer) key);
}
g_signal_emit_by_name(diya_shell_object_get_shell(self), DIYA_SIGNAL_SHELL_KEYBOARD_ENTER, self->xkb_keymap, self->xkb_state, (void*) keys_list);
g_list_free(keys_list);
}
static void wl_keyboard_key(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
{
(void)keyboard;
(void)serial;
(void)time;
DiyaInput *self = data;
if(state == WL_KEYBOARD_KEY_STATE_PRESSED)
{
g_signal_emit_by_name(diya_shell_object_get_shell(self), DIYA_SIGNAL_SHELL_KEY_PRESSED, self->xkb_keymap, self->xkb_state, key, time);
}
else
{
g_signal_emit_by_name(diya_shell_object_get_shell(self), DIYA_SIGNAL_SHELL_KEY_RELEASED, self->xkb_keymap, self->xkb_state, key, time);
}
}
static void wl_keyboard_leave(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface)
{
(void)keyboard;
(void)serial;
(void)surface;
DiyaInput *self = data;
g_signal_emit_by_name(diya_shell_object_get_shell(self), DIYA_SIGNAL_SHELL_KEYBOARD_LEAVE);
}
static void wl_keyboard_modifiers(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed,
uint32_t mods_latched, uint32_t mods_locked,
uint32_t group)
{
(void)keyboard;
(void)serial;
DiyaInput *self = data;
xkb_state_update_mask(self->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
g_signal_emit_by_name(diya_shell_object_get_shell(self), DIYA_SIGNAL_SHELL_KEYBOARD_MODIFIER_CHANGED, self->xkb_keymap, (void*) self->xkb_state);
}
static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
{
(void)data;
(void)keyboard;
(void)rate;
(void)delay;
}
static const struct wl_keyboard_listener wl_keyboard_listener = {
.keymap = wl_keyboard_keymap,
.enter = wl_keyboard_enter,
.leave = wl_keyboard_leave,
.key = wl_keyboard_key,
.modifiers = wl_keyboard_modifiers,
.repeat_info = wl_keyboard_repeat_info,
};
static void wl_seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities)
{
DiyaInput *self = data;
bool have_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD;
if (have_keyboard && self->keyboard == NULL)
{
self->keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(self->keyboard, &wl_keyboard_listener, self);
}
else if (!have_keyboard && self->keyboard != NULL)
{
wl_keyboard_release(self->keyboard);
self->keyboard = NULL;
}
}
static void wl_seat_name(void *data, struct wl_seat *seat, const char *name)
{
(void)seat;
DiyaInput *self = data;
if (self->name)
{
return;
}
g_info("Attach to seat: %s", name);
self->name = g_strdup(name);
}
static const struct wl_seat_listener wl_seat_listener = {
.capabilities = wl_seat_capabilities,
.name = wl_seat_name,
};
DiyaInput *diya_input_new(DiyaShell *shell)
{
assert(shell);
DiyaInput *self = g_object_new(DIYA_TYPE_INPUT, "shell", shell, NULL);
DiyaWayland *wayland = diya_shell_get_wayland(shell);
assert(wayland);
struct wl_seat *seat = diya_wayland_get_seat(wayland);
assert(seat);
wl_seat_add_listener(seat, &wl_seat_listener, self);
return self;
}

12
src/input.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef DIYA_INPUT_H
#define DIYA_INPUT_H
#include "base.h"
USE_CLASS(DiyaShell);
#define DIYA_TYPE_INPUT (diya_input_get_type ())
G_DECLARE_FINAL_TYPE (DiyaInput, diya_input, DIYA, INPUT, DiyaShellObject)
DiyaInput* diya_input_new(DiyaShell* shell);
#endif

View File

@ -1,95 +1,165 @@
#include "launcher.h" #include <wayland-client-protocol.h>
#include "foreign.h" #include <gdk/wayland/gdkwayland.h>
#include "session-lock.h"
#include <assert.h> #include <assert.h>
#include "launcher.h"
#include "widgets/dashboard-widget.h"
#include "widgets/taskbar-widget.h"
#include "foreign.h"
#include "wayland.h"
#define NAMESPACE "launcher" struct _DiyaLauncher
static void on_launcher_destroy(GtkWindow *window, GApplication *_data)
{ {
(void) window; DiyaShellObject parent;
(void)_data; DiyaDashboardWidget* dashboard;
//g_application_quit (G_APPLICATION (gtk_window_get_application (window))); DiyaTaskbarWidget* taskbar;
} };
G_DEFINE_FINAL_TYPE(DiyaLauncher, diya_launcher, DIYA_TYPE_SHELL_OBJECT)
static void on_foreign_window_change(DiyaSessionShell* shell, DiyaForeignWindow * win, gpointer data) enum
{ {
(void) data; NO_PROP,
assert(win); PROP_DASHBOARD,
assert(shell); PROP_TASKBAR,
g_warning("on_foreign_window_change: WINDOW CHANGE %s, shell %s", diya_object_to_string(DIYA_OBJECT(win)), diya_object_to_string(DIYA_OBJECT(shell))); N_PROPERTIES
} };
static void on_foreign_window_removed(DiyaSessionShell* shell, DiyaForeignWindow * win, gpointer data) static GParamSpec *g_prop[N_PROPERTIES] = {0};
{
(void) data;
assert(win);
assert(shell);
g_warning("on_foreign_window_removed: WINDOW REMOVED %s, shell %s", diya_object_to_string(DIYA_OBJECT(win)), diya_object_to_string(DIYA_OBJECT(shell)));
}
static void session_lock(GtkWidget *widget,gpointer data) /*
static void show_windows(GtkWidget *widget,gpointer data)
{ {
(void) widget; (void) widget;
g_warning("Enter session lock"); g_warning("Show all windows");
diya_session_shell_lock(data); DiyaSessionShell * shell = DIYA_SESSION_SHELL(data);
assert(shell);
GHashTable* windows = NULL;
g_object_get(shell, DIYA_PROP_SESSION_WINDOWS, &windows, NULL);
assert(windows);
GHashTableIter iter;
gpointer handle;
DiyaForeignWindow* window;
g_hash_table_iter_init (&iter, windows);
while (g_hash_table_iter_next(&iter, (gpointer) &handle, (gpointer) &window))
{
g_warning("unset minimized %s", diya_object_to_string(window));
diya_foreign_window_set_state(window, DIYA_WIN_STATE_MINIMIZE, false);
}
}
*/
static void diya_launcher_dispose(GObject* object)
{
(void) object;
DiyaLauncher * self = DIYA_LAUNCHER(object);
g_debug("diya_launcher_dispose: %s", diya_object_to_string(object));
if(self->dashboard)
{
gtk_window_destroy(GTK_WINDOW(self->dashboard));
self->dashboard = NULL;
}
if(self->taskbar)
{
gtk_window_destroy(GTK_WINDOW(self->taskbar));
self->taskbar = NULL;
}
G_OBJECT_CLASS(diya_launcher_parent_class)->dispose(object);
}
static void diya_launcher_init(DiyaLauncher * self)
{
self->taskbar = NULL;
self->dashboard = NULL;
}
static const gchar* diya_launcher_to_string(DiyaObject* object)
{
(void) object;
return "DiyaLauncher";
}
static void diya_launcher_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
DiyaLauncher * self = DIYA_LAUNCHER(object);
switch (property_id)
{
case PROP_DASHBOARD:
self->dashboard = g_value_get_pointer(value);
break;
case PROP_TASKBAR:
self->taskbar = g_value_get_pointer(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void diya_launcher_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
DiyaLauncher * self = DIYA_LAUNCHER(object);
switch (property_id)
{
case PROP_DASHBOARD:
g_value_set_pointer(value, self->dashboard);
break;
case PROP_TASKBAR:
g_value_set_pointer(value, self->taskbar);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void diya_launcher_class_init(DiyaLauncherClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_launcher_dispose;
gobject_class->set_property = diya_launcher_set_property;
gobject_class->get_property = diya_launcher_get_property;
base_class->to_string = diya_launcher_to_string;
g_prop[PROP_DASHBOARD] = g_param_spec_pointer(DIYA_PROP_LAUNCHER_DASHBOARD, NULL, "Launcher dashboard", G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_prop[PROP_TASKBAR] = g_param_spec_pointer(DIYA_PROP_LAUNCHER_TASKBAR, NULL, "Launcher taskbar", G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, N_PROPERTIES, g_prop);
} }
void diya_session_shell_launcher_init(DiyaSessionShell * shell) void diya_session_shell_launcher_init(DiyaSessionShell * shell)
{ {
assert(shell); DiyaDashboardWidget* dashboard = DIYA_DASHBOARD_WIDGET(diya_shell_window_new(DIYA_TYPE_DASHBOARD_WIDGET, shell));
GtkApplication * app; assert(dashboard);
g_object_get(shell, "application", &app, NULL); DiyaTaskbarWidget* taskbar = DIYA_TASKBAR_WIDGET(diya_shell_window_new(DIYA_TYPE_TASKBAR_WIDGET, shell));
assert(app); assert(taskbar);
GtkWindow *gtk_window = GTK_WINDOW (gtk_application_window_new (app)); //gtk_window_set_transient_for(GTK_WINDOW(dashboard), GTK_WINDOW(taskbar));
assert(gtk_window); DiyaLauncher* self = DIYA_LAUNCHER(g_object_new (DIYA_TYPE_LAUNCHER, "dashboard", dashboard, "taskbar",taskbar, NULL));
g_object_set(shell, "launchpad", gtk_window, NULL); assert(self);
g_object_bind_property(taskbar, DIYA_PROP_TASKBAR_SHOW_DASHBOARD, dashboard, DIYA_PROP_DASHBOARD_ACTIVE, G_BINDING_BIDIRECTIONAL);
g_object_set(shell, "launchpad", self, NULL);
//g_signal_connect (GTK_WINDOW(dashboard), "destroy", G_CALLBACK (on_launcher_destroy), NULL);
g_signal_connect (gtk_window, "destroy", G_CALLBACK (on_launcher_destroy), NULL); gtk_window_present (GTK_WINDOW (taskbar));
// 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 GtkIconTheme* theme = gtk_icon_theme_get_for_display(gdk_display_get_default());
for (int i = 0; i < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; i++) char**icons = gtk_icon_theme_get_icon_names (theme);
gtk_layer_set_margin (gtk_window, i, 0); g_warning("List all icons");
gtk_layer_set_layer (gtk_window, GTK_LAYER_SHELL_LAYER_TOP); for(int i = 0; icons[i] != NULL; i++)
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_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));
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_debug("ICON: %s", icons[i]);
g_warning("%s", g_app_info_get_display_name(element_data));
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); }
void diya_launcher_show_dashboard(DiyaLauncher* self, gboolean value)
{
g_object_set(self->dashboard, DIYA_PROP_DASHBOARD_ACTIVE, value, NULL);
}
void diya_launcher_toggle_dashboard(DiyaLauncher* self)
{
diya_launcher_show_dashboard(self, !diya_dashboard_is_active(self->dashboard));
} }

View File

@ -1,7 +1,18 @@
#ifndef DIYA_SHELL_LAUNCHER_H #ifndef DIYA_SHELL_LAUNCHER_H
#define DIYA_SHELL_LAUNCHER_H #define DIYA_SHELL_LAUNCHER_H
#include "session-shell.h" #include "base.h"
USE_CLASS(DiyaSessionShell);
#define DIYA_PROP_LAUNCHER_DASHBOARD "dashboard"
#define DIYA_PROP_LAUNCHER_TASKBAR "taskbar"
#define DIYA_TYPE_LAUNCHER (diya_launcher_get_type ())
G_DECLARE_FINAL_TYPE (DiyaLauncher, diya_launcher, DIYA, LAUNCHER, DiyaShellObject)
void diya_launcher_show_dashboard(DiyaLauncher* self, gboolean value);
void diya_launcher_toggle_dashboard(DiyaLauncher* self);
void diya_session_shell_launcher_init(DiyaSessionShell * shell); void diya_session_shell_launcher_init(DiyaSessionShell * shell);

View File

@ -3,25 +3,39 @@
#include <gio/gio.h> #include <gio/gio.h>
#include "login-shell.h" #include "login-shell.h"
#include "virtual-keyboard.h" #include "widgets/virtual-keyboard-widgets.h"
#define DBUS_SERVER_NAME "dev.iohub.diya.SessionManager" #define DBUS_SERVER_NAME "dev.iohub.diya.SessionManager"
#define DBUS_SERVER_PATH "/dev/iohub/diya/SessionManager" #define DBUS_SERVER_PATH "/dev/iohub/diya/SessionManager"
#define DBUS_SERVER_ERROR_NAME "dev.iohub.diya.SessionManager.Error" #define DBUS_SERVER_ERROR_NAME "dev.iohub.diya.SessionManager.Error"
#define NAMESPACE "diya_login_shell"
struct _DiyaLoginShell struct _DiyaLoginShell
{ {
DiyaShell parent_object; DiyaShell parent_object;
GtkApplication *app;
GtkSessionLockInstance *lock; GtkSessionLockInstance *lock;
GtkWidget *username; GtkWidget *username;
GtkWidget *password; GtkWidget *password;
GtkWidget *status; GtkWidget *status;
guint bus_watch_id; guint bus_watch_id;
GtkWidget *vkb_widget;
GtkWidget *revealer;
GList *windows;
}; };
G_DEFINE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA_TYPE_SHELL); G_DEFINE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA_TYPE_SHELL);
static void diya_login_shell_finalize(GObject *object)
{
DiyaLoginShell *self = DIYA_LOGIN_SHELL(object);
g_debug("diya_login_shell_finalize: %s", diya_object_to_string(self));
if (self->windows)
{
g_list_free(self->windows);
}
G_OBJECT_CLASS(diya_login_shell_parent_class)->finalize(object);
}
static void diya_login_shell_dispose(GObject *object) static void diya_login_shell_dispose(GObject *object)
{ {
DiyaLoginShell *self = DIYA_LOGIN_SHELL(object); DiyaLoginShell *self = DIYA_LOGIN_SHELL(object);
@ -34,47 +48,37 @@ static void diya_login_shell_dispose(GObject *object)
} }
g_object_unref(self->lock); g_object_unref(self->lock);
} }
if (self->windows)
{
// destroyed all windows and free list
GList *it = NULL;
for (it = self->windows; it; it = it->next)
{
if (it->data)
{
gtk_window_destroy(GTK_WINDOW(it->data));
}
}
// g_list_free(self->windows);
}
if (self->bus_watch_id > 0) if (self->bus_watch_id > 0)
{ {
g_bus_unwatch_name(self->bus_watch_id); g_bus_unwatch_name(self->bus_watch_id);
} }
if (self->app)
{
g_object_unref(self->app);
}
G_OBJECT_CLASS(diya_login_shell_parent_class)->dispose(object); G_OBJECT_CLASS(diya_login_shell_parent_class)->dispose(object);
} }
static void diya_login_shell_init(DiyaLoginShell *self) static void diya_login_shell_init(DiyaLoginShell *self)
{ {
self->app = NULL; g_debug("diya_login_shell_init");
self->lock = gtk_session_lock_instance_new(); self->lock = gtk_session_lock_instance_new();
self->username = NULL; self->username = NULL;
self->password = NULL; self->password = NULL;
self->status = NULL;
self->windows = NULL;
self->bus_watch_id = 0; self->bus_watch_id = 0;
} }
static const gchar *diya_login_shell_to_string(DiyaObject *object)
{
(void)object;
return "Diya Login Shell";
}
static void diya_login_shell_class_init(DiyaLoginShellClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_login_shell_dispose;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
//DiyaShellClass *base_shell_class = DIYA_SHELL_CLASS(class)
//base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register;
base_class->to_string = diya_login_shell_to_string;
}
static void on_method_call_return(GObject *source_object, GAsyncResult *res, gpointer user_data) static void on_method_call_return(GObject *source_object, GAsyncResult *res, gpointer user_data)
{ {
(void)source_object; (void)source_object;
@ -103,14 +107,14 @@ static void on_method_call_return(GObject *source_object, GAsyncResult *res, gpo
if (success) if (success)
{ {
gtk_label_set_text(GTK_LABEL(self->status), "Login successful"); gtk_label_set_text(GTK_LABEL(self->status), "Login successful");
g_application_quit(G_APPLICATION(self->app)); g_object_unref(self);
} }
else else
{ {
gtk_label_set_text(GTK_LABEL(self->status), "Login failed! Please try again."); gtk_label_set_text(GTK_LABEL(self->status), "Login failed! Please try again.");
} }
g_variant_unref(result); g_variant_unref(result);
//g_object_unref(reply); // g_object_unref(reply);
} }
static void on_name_appeared(GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) static void on_name_appeared(GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data)
@ -131,7 +135,7 @@ static void on_name_appeared(GDBusConnection *connection, const gchar *name, con
g_dbus_message_set_body(request, g_variant_new("(ss)", username, password)); g_dbus_message_set_body(request, g_variant_new("(ss)", username, password));
g_dbus_connection_send_message_with_reply(connection, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, on_method_call_return, self); g_dbus_connection_send_message_with_reply(connection, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, on_method_call_return, self);
g_object_unref(request); g_object_unref(request);
g_bus_unwatch_name (self->bus_watch_id); g_bus_unwatch_name(self->bus_watch_id);
self->bus_watch_id = 0; self->bus_watch_id = 0;
} }
@ -174,129 +178,167 @@ static void do_login(GtkButton *button, DiyaLoginShell *self)
// g_application_quit(G_APPLICATION(self->app)); // g_application_quit(G_APPLICATION(self->app));
} }
static void open_vkb(GtkButton *button, DiyaLoginShell *self) static void add_new_monitor(DiyaLoginShell *self, GdkMonitor *monitor, gint position)
{ {
(void) button; GtkWindow *window = GTK_WINDOW(gtk_application_window_new(diya_shell_get_application(DIYA_SHELL(self))));
DiyaVirtualKeyboard* vkb = diya_virtual_keyboard_new(DIYA_SHELL(self), NULL); gtk_session_lock_instance_assign_window_to_monitor(self->lock, window, monitor);
if(!vkb) gtk_widget_set_name(GTK_WIDGET(window), NAMESPACE);
{
return;
}
g_warning("Sending A to: %s", diya_object_to_string(DIYA_OBJECT(vkb)));
diya_virtual_keyboard_send_key(vkb,30, VKB_KEY_STATE_PRESSED);
g_usleep(10000);
diya_virtual_keyboard_send_key(vkb,30, VKB_KEY_STATE_RELEASED);
g_usleep(10000);
// send example key
g_object_unref(vkb);
}
DiyaLoginShell *diya_login_shell_new() GtkWidget *grid = gtk_grid_new();
{ gtk_window_set_child(window, grid);
return g_object_new(DIYA_TYPE_LOGIN_SHELL, NULL); gtk_grid_set_row_homogeneous(GTK_GRID(grid), false);
}
void diya_login_shell_attach(DiyaLoginShell *self, GtkApplication *app)
{
self->app = app;
if (!gtk_session_lock_instance_lock(self->lock))
{
g_error("gtk_session_lock_instance_lock: Unable to lock the display");
g_object_unref(self);
return;
}
GdkDisplay *display = gdk_display_get_default();
GListModel *monitors = gdk_display_get_monitors(display);
guint n_monitors = g_list_model_get_n_items(monitors);
for (guint i = 0; i < n_monitors; ++i)
{
GdkMonitor *monitor = g_list_model_get_item(monitors, i);
GtkWindow *gtk_window = GTK_WINDOW(gtk_application_window_new(app));
gtk_session_lock_instance_assign_window_to_monitor(self->lock, gtk_window, monitor);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER); gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER); gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_box_set_spacing(GTK_BOX(box), 10); gtk_box_set_spacing(GTK_BOX(box), 10);
gtk_widget_set_hexpand(box, true);
gtk_widget_set_vexpand(box, true);
GtkWidget *label; GtkWidget *label;
label = gtk_label_new("Please login"); label = gtk_label_new("Please login");
gtk_box_append(GTK_BOX(box), label); gtk_box_append(GTK_BOX(box), label);
gtk_widget_add_css_class(label, "header"); gtk_widget_add_css_class(label, "diya-login-header");
GtkWidget *user_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_valign(user_box, GTK_ALIGN_CENTER);
gtk_widget_set_halign(user_box, GTK_ALIGN_END);
gtk_box_set_spacing(GTK_BOX(user_box), 10);
GtkWidget *child_grid = gtk_grid_new();
gtk_grid_set_row_spacing(GTK_GRID(child_grid),10);
gtk_grid_set_column_spacing(GTK_GRID(child_grid),10);
label = gtk_label_new("Username"); label = gtk_label_new("Username");
gtk_box_append(GTK_BOX(user_box), label); gtk_grid_attach(GTK_GRID(child_grid), label, 0, 0, 1, 1);
self->username = gtk_entry_new(); self->username = gtk_entry_new();
gtk_box_append(GTK_BOX(user_box), GTK_WIDGET(self->username)); gtk_grid_attach(GTK_GRID(child_grid), self->username, 1, 0, 1, 1);
gtk_box_append(GTK_BOX(box), user_box);
GtkWidget *password_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_valign(password_box, GTK_ALIGN_CENTER);
gtk_widget_set_halign(password_box, GTK_ALIGN_END);
gtk_box_set_spacing(GTK_BOX(password_box), 10);
label = gtk_label_new("Password"); label = gtk_label_new("Password");
gtk_box_append(GTK_BOX(password_box), label); gtk_grid_attach(GTK_GRID(child_grid), label, 0, 1, 1, 1);
self->password = gtk_password_entry_new(); self->password = gtk_password_entry_new();
gtk_box_append(GTK_BOX(password_box), GTK_WIDGET(self->password)); gtk_grid_attach(GTK_GRID(child_grid), self->password, 1, 1, 1, 1);
gtk_box_append(GTK_BOX(box), password_box); gtk_box_append(GTK_BOX(box), child_grid);
g_signal_connect(self->username, "activate", G_CALLBACK(do_login), self); g_signal_connect(self->username, "activate", G_CALLBACK(do_login), self);
g_signal_connect(self->password, "activate", G_CALLBACK(do_login), self); g_signal_connect(self->password, "activate", G_CALLBACK(do_login), self);
child_grid = gtk_grid_new();
gtk_grid_set_column_spacing(GTK_GRID(child_grid),2);
GtkWidget *button = gtk_button_new_with_label("Login"); GtkWidget *button = gtk_button_new_with_label("Login");
g_signal_connect(button, "clicked", G_CALLBACK(do_login), self); g_signal_connect(button, "clicked", G_CALLBACK(do_login), self);
//gtk_widget_set_can_focus(GTK_WIDGET(button), false); gtk_widget_set_can_focus(GTK_WIDGET(button), false);
gtk_box_append(GTK_BOX(box), button); gtk_grid_attach(GTK_GRID(child_grid), button, 0, 0, 1, 1);
// Not displayed, but allows testing that creating popups doesn't crash GTK // Not displayed, but allows testing that creating popups doesn't crash GTK
gtk_widget_set_tooltip_text(button, "Login"); gtk_widget_set_tooltip_text(button, "Login");
gtk_widget_set_hexpand(button, true);
button = gtk_toggle_button_new_with_label("");
gtk_widget_add_css_class(button, "diya-btn-show-vkb");
gtk_grid_attach(GTK_GRID(child_grid), button, 1, 0, 1, 1);
gtk_box_append(GTK_BOX(box), child_grid);
gtk_widget_set_tooltip_text(button, "Show virtual keyboard");
gtk_widget_set_can_focus(GTK_WIDGET(button), false);
self->status = gtk_label_new(NULL); self->status = gtk_label_new(NULL);
gtk_box_append(GTK_BOX(box), self->status); gtk_box_append(GTK_BOX(box), self->status);
gtk_widget_add_css_class(self->status, "status"); gtk_widget_add_css_class(self->status, "diya-login-status");
button = gtk_button_new_with_label("Show virtual keyboard"); gtk_grid_attach(GTK_GRID(grid), box, 0, 0, 1, 1);
g_signal_connect(button, "clicked", G_CALLBACK(open_vkb), self);
gtk_widget_set_can_focus(GTK_WIDGET(button), false);
gtk_box_append(GTK_BOX(box), button);
gtk_window_set_child(GTK_WINDOW(gtk_window), box); box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_box_set_spacing(GTK_BOX(box), 10);
gtk_window_present(gtk_window); self->revealer = gtk_revealer_new();
} self->vkb_widget = diya_virtual_keyboard_widget_new(diya_shell_get_virtual_keyboard(DIYA_SHELL(self), g_getenv(DIYA_ENV_VKB_KEYMAP)));
// load xml content from gresource gtk_revealer_set_child(GTK_REVEALER(self->revealer), self->vkb_widget);
GError *err = NULL; gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), false);
GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/shell/login-shell.css", 0, &err); gtk_revealer_set_transition_type(GTK_REVEALER(self->revealer),GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
if (err != NULL) gtk_box_append(GTK_BOX(box), self->revealer);
g_object_bind_property(button, "active", self->revealer, "reveal-child",G_BINDING_BIDIRECTIONAL);
//gtk_widget_set_visible(self->vkb_widget, false);
gtk_grid_attach(GTK_GRID(grid), box, 0, 1, 1, 1);
gtk_widget_set_hexpand(box, true);
gtk_widget_set_vexpand(box, false);
gtk_window_present(window);
self->windows = g_list_insert(self->windows, window, position);
}
static void on_monitor_changed(GListModel *monitor_lists, guint position, guint removed, guint added, gpointer object)
{
g_debug("Monitor list changed at %d: added %d, removed %d", position, added, removed);
DiyaLoginShell *self = DIYA_LOGIN_SHELL(object);
if (removed > 0)
{ {
g_critical("Unable to load CSS resource: %s", err->message); for (guint i = 0; i < removed; i++)
g_error_free(err);
return;
}
else
{ {
const char *data = g_bytes_get_data(bytes, NULL); GtkWindow *win = GTK_WINDOW(g_list_nth(self->windows, position));
g_debug("CSS resource loaded:\n %s", data); if (win)
GtkCssProvider *provider = gtk_css_provider_new(); {
gtk_css_provider_load_from_string(provider, data); gtk_window_destroy(win);
gtk_style_context_add_provider_for_display( self->windows = g_list_remove(self->windows, win);
gdk_display_get_default(), }
GTK_STYLE_PROVIDER(provider), }
GTK_STYLE_PROVIDER_PRIORITY_USER); }
g_bytes_unref(bytes); if (added > 0)
{
for (guint i = 0; i < added; i++)
{
GdkMonitor *monitor = g_list_model_get_item(monitor_lists, position + i);
add_new_monitor(self, monitor, position + i);
}
} }
} }
static void diya_login_on_shell_idle(DiyaShell* shell)
{
(void) shell;
g_debug("diya_login_on_shell_idle");
diya_shell_power_display(shell, false);
}
static void diya_login_on_shell_resume(DiyaShell* shell)
{
(void) shell;
g_debug("diya_login_on_shell_resume");
diya_shell_power_display(shell, true);
}
static void diya_login_shell_startup(DiyaShell *shell)
{
DiyaLoginShell *self = DIYA_LOGIN_SHELL(shell);
if (!gtk_session_lock_instance_lock(self->lock))
{
g_object_unref(self);
g_error("gtk_session_lock_instance_lock: Unable to lock the display");
return;
}
GListModel *list = gdk_display_get_monitors(gdk_display_get_default());
for (guint i = 0; i < g_list_model_get_n_items(list); i++)
{
GdkMonitor *monitor = g_list_model_get_item(list, i);
add_new_monitor(self, monitor, -1);
}
g_signal_connect(shell, DIYA_SIGNAL_SHELL_IDLE, G_CALLBACK(diya_login_on_shell_idle), NULL);
g_signal_connect(shell, DIYA_SIGNAL_SHELL_RESUME, G_CALLBACK(diya_login_on_shell_resume), NULL);
}
static void diya_login_shell_class_init(DiyaLoginShellClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_login_shell_dispose;
gobject_class->finalize = diya_login_shell_finalize;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
DiyaShellClass *base_shell_class = DIYA_SHELL_CLASS(class);
base_shell_class->monitor_changed_handle = on_monitor_changed;
base_shell_class->startup_handle = diya_login_shell_startup;
// base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register;
}

View File

@ -8,8 +8,4 @@
#define DIYA_TYPE_LOGIN_SHELL (diya_login_shell_get_type()) #define DIYA_TYPE_LOGIN_SHELL (diya_login_shell_get_type())
G_DECLARE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA, LOGIN_SHELL, DiyaShell); G_DECLARE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA, LOGIN_SHELL, DiyaShell);
DiyaLoginShell *diya_login_shell_new();
void diya_login_shell_attach(DiyaLoginShell *self, GtkApplication *app);
#endif #endif

View File

@ -2,58 +2,10 @@
#include <assert.h> #include <assert.h>
#include "login-shell.h" #include "login-shell.h"
#include "wayland.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, DiyaLoginShell* shell)
{
diya_shell_wayland_init(DIYA_SHELL(shell));
g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL);
g_unix_signal_add(SIGINT,(GSourceFunc)g_application_quit,(void*)app);
diya_login_shell_attach(shell, app);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
g_shell_argv = g_malloc0(sizeof(gchar *) * (argc + 1)); DiyaLoginShell* shell = DIYA_LOGIN_SHELL(g_object_new(DIYA_TYPE_LOGIN_SHELL, "name", "dev.iohub.diya.login-shell", NULL));
for (int i = 0; i < argc; i++) return diya_shell_run(DIYA_SHELL(shell), argc, argv);
{
g_shell_argv[i] = argv[i];
}
GtkApplication* app = gtk_application_new("dev.iohub.diya.login-shell", G_APPLICATION_DEFAULT_FLAGS);
DiyaLoginShell* shell = diya_login_shell_new();
g_signal_connect(app, "startup", G_CALLBACK(startup), shell);
g_signal_connect(app, "activate", G_CALLBACK(activate), 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(shell);
return status;
} }

View File

@ -14,7 +14,7 @@ void diya_session_shell_lock(DiyaSessionShell* shell)
{ {
assert(shell); assert(shell);
GtkSessionLockInstance * lock; GtkSessionLockInstance * lock;
g_object_get(shell, "session-lock", &lock, NULL); g_object_get(shell, DIYA_PROP_SESSION_LOCK, &lock, NULL);
assert(lock); assert(lock);
if(gtk_session_lock_instance_is_locked(lock)) if(gtk_session_lock_instance_is_locked(lock))
{ {
@ -27,7 +27,7 @@ void diya_session_shell_lock(DiyaSessionShell* shell)
return; return;
} }
GtkApplication * app; GtkApplication * app;
g_object_get(shell, "application", &app, NULL); g_object_get(shell, DIYA_PROP_SHELL_APPLICATION, &app, NULL);
assert(app); assert(app);
GdkDisplay *display = gdk_display_get_default(); GdkDisplay *display = gdk_display_get_default();
@ -64,7 +64,7 @@ void diya_session_shell_unlock(DiyaSessionShell* shell)
{ {
assert(shell); assert(shell);
GtkSessionLockInstance * lock; GtkSessionLockInstance * lock;
g_object_get(shell, "session-lock", &lock, NULL); g_object_get(shell, DIYA_PROP_SESSION_LOCK, &lock, NULL);
assert(lock); assert(lock);
gtk_session_lock_instance_unlock(lock); gtk_session_lock_instance_unlock(lock);
g_debug("gtk_session_lock_instance_unlock: Shell unlocked"); g_debug("gtk_session_lock_instance_unlock: Shell unlocked");

View File

@ -2,15 +2,17 @@
#include <assert.h> #include <assert.h>
#include <gtk4-session-lock.h> #include <gtk4-session-lock.h>
#include <xkbcommon/xkbcommon.h>
#include "shell.h" #include "shell.h"
#include "foreign.h" #include "foreign.h"
#include "background.h"
#define SHELL_DESCRIPTION "Diya GTK shell for wayland (diyac)" #include "launcher.h"
#include "session-lock.h"
#include "idle.h"
enum enum
{ {
NO_PROP, NO_PROP,
SHELL_APP,
SHELL_BACKGROUND_WIDGET, SHELL_BACKGROUND_WIDGET,
SHELL_LAUNCHPAD_WIDGET, SHELL_LAUNCHPAD_WIDGET,
SHELL_LOCK_SESSION, SHELL_LOCK_SESSION,
@ -23,35 +25,46 @@ static GParamSpec *shell_properties[N_PROPERTIES] = {0};
struct _DiyaSessionShell struct _DiyaSessionShell
{ {
DiyaShell parent; DiyaShell parent;
GtkApplication* app; GtkWindow *background;
GtkWindow* background; DiyaLauncher *launcher;
GtkWindow* launcher; GHashTable *windows;
GHashTable* windows; GtkSessionLockInstance *lock;
GtkSessionLockInstance* lock;
}; };
G_DEFINE_FINAL_TYPE(DiyaSessionShell, diya_session_shell, DIYA_TYPE_SHELL) G_DEFINE_FINAL_TYPE(DiyaSessionShell, diya_session_shell, DIYA_TYPE_SHELL)
static void diya_session_shell_dispose(GObject* object) static void diya_session_shell_finalize(GObject *object)
{ {
DiyaSessionShell * self = DIYA_SESSION_SHELL(object); DiyaSessionShell *self = DIYA_SESSION_SHELL(object);
g_hash_table_destroy(self->windows); g_hash_table_destroy(self->windows);
g_debug("diya_session_shell_dispose"); g_debug("diya_session_shell_finalize: %s", diya_object_to_string(object));
if(self->lock) G_OBJECT_CLASS(diya_session_shell_parent_class)->finalize(object);
}
static void diya_session_shell_dispose(GObject *object)
{
DiyaSessionShell *self = DIYA_SESSION_SHELL(object);
// g_hash_table_destroy(self->windows);
g_debug("diya_session_shell_dispose: %s", diya_object_to_string(object));
if (self->lock)
{ {
g_object_unref(self->lock); g_object_unref(self->lock);
} }
if (self->background)
{
gtk_window_destroy(self->background);
}
if (self->launcher)
{
g_object_unref(self->launcher);
}
G_OBJECT_CLASS(diya_session_shell_parent_class)->dispose(object); G_OBJECT_CLASS(diya_session_shell_parent_class)->dispose(object);
} }
static void diya_session_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) static void diya_session_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{ {
DiyaSessionShell * self = DIYA_SESSION_SHELL(object); DiyaSessionShell *self = DIYA_SESSION_SHELL(object);
switch (property_id) switch (property_id)
{ {
case SHELL_APP:
self->app = g_value_get_pointer(value);
assert(self->app);
break;
case SHELL_BACKGROUND_WIDGET: case SHELL_BACKGROUND_WIDGET:
self->background = g_value_get_pointer(value); self->background = g_value_get_pointer(value);
break; break;
@ -59,22 +72,19 @@ static void diya_session_shell_set_property(GObject *object, guint property_id,
self->launcher = g_value_get_pointer(value); self->launcher = g_value_get_pointer(value);
break; break;
case SHELL_WINDOWS: case SHELL_WINDOWS:
//self->windows = g_value_get_pointer(value); // self->windows = g_value_get_pointer(value);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break; break;
} }
} }
static void diya_session_shell_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) static void diya_session_shell_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{ {
DiyaSessionShell * self = DIYA_SESSION_SHELL(object); DiyaSessionShell *self = DIYA_SESSION_SHELL(object);
switch (property_id) switch (property_id)
{ {
case SHELL_APP:
g_value_set_pointer(value, self->app);
break;
case SHELL_BACKGROUND_WIDGET: case SHELL_BACKGROUND_WIDGET:
g_value_set_pointer(value, self->background); g_value_set_pointer(value, self->background);
break; break;
@ -90,39 +100,95 @@ static void diya_session_shell_get_property(GObject *object, guint property_id,
g_value_set_pointer(value, self->windows); g_value_set_pointer(value, self->windows);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break; break;
} }
} }
static const gchar* diya_session_shell_to_string(DiyaObject* object) static void diya_session_on_key_pressed(DiyaShell* shell, struct xkb_keymap *xkb_keymap, struct xkb_state *xkb_state, uint32_t key, uint32_t time, gpointer userdata)
{ {
(void) object; (void) xkb_keymap;
return SHELL_DESCRIPTION; (void) userdata;
(void) time;
DiyaSessionShell* self = DIYA_SESSION_SHELL(shell);
uint32_t keycode = key + 8;
xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, keycode);
g_debug("Key press %d", sym);
switch(sym)
{
case XKB_KEY_Escape:
diya_launcher_show_dashboard(self->launcher, false);
break;
case XKB_KEY_space:
if(xkb_state_mod_name_is_active(xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE)) {
diya_launcher_toggle_dashboard(self->launcher);
}
default:
break;
}
/*
char buf[128];
xkb_keysym_get_name(sym, buf, sizeof(buf));
g_warning("key-pressed (%d): sym: %-12s (%d)", time, buf, sym);
xkb_state_key_get_utf8(xkb_state, keycode, buf, sizeof(buf));
g_warning("\tutf8: '%s'", buf);
*/
}
static void diya_session_on_shell_idle(DiyaShell* shell)
{
(void) shell;
g_debug("diya_session_on_shell_idle");
diya_shell_power_display(shell, false);
}
static void diya_session_on_shell_resume(DiyaShell* shell)
{
(void) shell;
g_debug("diya_session_on_shell_resume");
diya_shell_power_display(shell, true);
}
static void diya_session_shell_startup(DiyaShell *shell)
{
DiyaSessionShell* self = DIYA_SESSION_SHELL(shell);
diya_session_shell_init_background(self);
diya_session_shell_launcher_init(self);
g_signal_connect(shell, DIYA_SIGNAL_SHELL_KEY_PRESSED, G_CALLBACK(diya_session_on_key_pressed), NULL);
g_signal_connect(shell, DIYA_SIGNAL_SHELL_IDLE, G_CALLBACK(diya_session_on_shell_idle), NULL);
g_signal_connect(shell, DIYA_SIGNAL_SHELL_RESUME, G_CALLBACK(diya_session_on_shell_resume), NULL);
}
static void diya_session_shell_active(DiyaShell *shell)
{
diya_shell_monitor_input(shell);
} }
static void diya_session_shell_class_init(DiyaSessionShellClass *class) static void diya_session_shell_class_init(DiyaSessionShellClass *class)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS(class); GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class); // DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
DiyaShellClass *base_shell_class = DIYA_SHELL_CLASS(class); DiyaShellClass *base_shell_class = DIYA_SHELL_CLASS(class);
base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register; base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register;
base_shell_class->startup_handle = diya_session_shell_startup;
base_shell_class->active_handle = diya_session_shell_active;
base_class->to_string = diya_session_shell_to_string; /// base_class->to_string = diya_session_shell_to_string;
gobject_class->dispose = diya_session_shell_dispose; gobject_class->dispose = diya_session_shell_dispose;
gobject_class->finalize = diya_session_shell_finalize;
gobject_class->set_property = diya_session_shell_set_property; gobject_class->set_property = diya_session_shell_set_property;
gobject_class->get_property = diya_session_shell_get_property; gobject_class->get_property = diya_session_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(DIYA_PROP_SESSION_BACKGROUND, NULL, "Shell background widget", G_PARAM_READWRITE);
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(DIYA_PROP_SESSION_LAUNCHPAD, NULL, "Shell launchpad", G_PARAM_READWRITE);
shell_properties[SHELL_LAUNCHPAD_WIDGET] = g_param_spec_pointer("launchpad", NULL, "Shell launchpad", G_PARAM_READWRITE ); shell_properties[SHELL_LOCK_SESSION] = g_param_spec_pointer(DIYA_PROP_SESSION_LOCK, NULL, "Shell lock session", G_PARAM_READABLE);
shell_properties[SHELL_LOCK_SESSION] = g_param_spec_pointer("session-lock", NULL, "Shell lock session", G_PARAM_READABLE ); shell_properties[SHELL_WINDOWS] = g_param_spec_pointer(DIYA_PROP_SESSION_WINDOWS, NULL, "Shell foreign windows", 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_object_class_install_properties(gobject_class, N_PROPERTIES, shell_properties);
g_signal_new("foreign-window-changed", g_signal_new(DIYA_SIGNAL_FOREIGN_WINDOW_CHANGED,
DIYA_TYPE_SESSION_SHELL, DIYA_TYPE_SESSION_SHELL,
G_SIGNAL_DETAILED | G_SIGNAL_DETAILED |
G_SIGNAL_ACTION | G_SIGNAL_ACTION |
@ -134,7 +200,20 @@ static void diya_session_shell_class_init(DiyaSessionShellClass *class)
G_TYPE_NONE, G_TYPE_NONE,
1, 1,
G_TYPE_POINTER); G_TYPE_POINTER);
g_signal_new("foreign-window-removed", g_signal_new(DIYA_SIGNAL_FOREIGN_WINDOW_STATE_CHANGED,
DIYA_TYPE_SESSION_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
2,
G_TYPE_POINTER,
G_TYPE_UINT);
g_signal_new(DIYA_SIGNAL_FOREIGN_WINDOW_ADDED,
DIYA_TYPE_SESSION_SHELL, DIYA_TYPE_SESSION_SHELL,
G_SIGNAL_DETAILED | G_SIGNAL_DETAILED |
G_SIGNAL_ACTION | G_SIGNAL_ACTION |
@ -146,7 +225,19 @@ static void diya_session_shell_class_init(DiyaSessionShellClass *class)
G_TYPE_NONE, G_TYPE_NONE,
1, 1,
G_TYPE_POINTER); G_TYPE_POINTER);
g_signal_new("session-locked", g_signal_new(DIYA_SIGNAL_FOREIGN_WINDOW_REMOVED,
DIYA_TYPE_SESSION_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(DIYA_SIGNAL_SESSION_LOCKED,
DIYA_TYPE_SESSION_SHELL, DIYA_TYPE_SESSION_SHELL,
G_SIGNAL_DETAILED | G_SIGNAL_DETAILED |
G_SIGNAL_ACTION | G_SIGNAL_ACTION |
@ -157,7 +248,7 @@ static void diya_session_shell_class_init(DiyaSessionShellClass *class)
NULL, NULL,
G_TYPE_NONE, G_TYPE_NONE,
0); 0);
g_signal_new("session-unlocked", g_signal_new(DIYA_SIGNAL_SESSION_UNLOCKED,
DIYA_TYPE_SESSION_SHELL, DIYA_TYPE_SESSION_SHELL,
G_SIGNAL_DETAILED | G_SIGNAL_DETAILED |
G_SIGNAL_ACTION | G_SIGNAL_ACTION |
@ -170,33 +261,25 @@ static void diya_session_shell_class_init(DiyaSessionShellClass *class)
0); 0);
} }
static void on_session_locked(GtkSessionLockInstance *lock, DiyaSessionShell *shell) { static void on_session_locked(GtkSessionLockInstance *lock, DiyaSessionShell *shell)
{
(void)lock; (void)lock;
assert(shell); assert(shell);
g_message("Session locked successfully"); g_message("Session locked successfully");
g_signal_emit_by_name(shell, "session-locked"); g_signal_emit_by_name(shell, DIYA_SIGNAL_SESSION_LOCKED);
} }
/* static void on_session_unlocked(GtkSessionLockInstance *lock, DiyaSessionShell *shell)
static void failed(GtkSessionLockInstance *lock, void *data) { {
(void)lock;
(void)data;
g_critical("The session could not be locked");
g_application_quit(G_APPLICATION(app));
}
*/
static void on_session_unlocked(GtkSessionLockInstance *lock, DiyaSessionShell *shell) {
(void)lock; (void)lock;
assert(shell); assert(shell);
g_message("Session unlocked"); g_message("Session unlocked");
g_signal_emit_by_name(shell, "session-unlocked"); g_signal_emit_by_name(shell, DIYA_SIGNAL_SESSION_UNLOCKED);
} }
static void diya_session_shell_init(DiyaSessionShell *self) static void diya_session_shell_init(DiyaSessionShell *self)
{ {
//self->app = NULL; // self->app = NULL;
self->background = NULL; self->background = NULL;
self->launcher = NULL; self->launcher = NULL;
self->lock = gtk_session_lock_instance_new(); self->lock = gtk_session_lock_instance_new();
@ -206,36 +289,32 @@ static void diya_session_shell_init(DiyaSessionShell *self)
self->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref); self->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
} }
DiyaForeignWindow* diya_session_shell_get_window(DiyaSessionShell * shell, gpointer handle) DiyaForeignWindow *diya_session_shell_get_window(DiyaSessionShell *shell, gpointer handle)
{ {
return g_hash_table_lookup(shell->windows, handle); return g_hash_table_lookup(shell->windows, handle);
} }
gboolean diya_session_shell_add_window(DiyaSessionShell * shell, DiyaForeignWindow * win) gboolean diya_session_shell_add_window(DiyaSessionShell *shell, DiyaForeignWindow *win)
{ {
gpointer handle; gpointer handle;
g_object_get(win, "handle", &handle, NULL); g_object_get(win, DIYA_PROP_FOREIGN_WINDOW_HANDLE, &handle, NULL);
assert(handle); assert(handle);
return g_hash_table_insert(shell->windows,handle, win); return g_hash_table_insert(shell->windows, handle, win);
} }
gboolean diya_session_shell_remove_window(DiyaSessionShell * shell, DiyaForeignWindow * win) gboolean diya_session_shell_remove_window(DiyaSessionShell *shell, DiyaForeignWindow *win)
{ {
gpointer handle; gpointer handle;
g_object_get(win, "handle", &handle, NULL); g_object_get(win, DIYA_PROP_FOREIGN_WINDOW_HANDLE, &handle, NULL);
assert(handle); assert(handle);
return g_hash_table_remove(shell->windows,handle); return g_hash_table_remove(shell->windows, handle);
} }
void diya_session_shell_remove_all_windows(DiyaSessionShell * shell) void diya_session_shell_remove_all_windows(DiyaSessionShell *shell)
{ {
g_hash_table_destroy(shell->windows); g_hash_table_destroy(shell->windows);
shell->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref); shell->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
} }
DiyaSessionShell * diya_session_shell_new(GtkApplication * app)
{
return DIYA_SESSION_SHELL(g_object_new(DIYA_TYPE_SESSION_SHELL,"application",app, NULL));
}
/* /*
static void on_orientation_changed (GtkWindow *window, WindowOrientation orientation, ToplevelData *data) static void on_orientation_changed (GtkWindow *window, WindowOrientation orientation, ToplevelData *data)
{ {

View File

@ -5,16 +5,25 @@
#include "shell.h" #include "shell.h"
#include "base.h" #include "base.h"
#define DIYA_SIGNAL_FOREIGN_WINDOW_CHANGED "foreign-window-changed"
#define DIYA_SIGNAL_FOREIGN_WINDOW_STATE_CHANGED "foreign-window-state-changed"
#define DIYA_SIGNAL_FOREIGN_WINDOW_ADDED "foreign-window-added"
#define DIYA_SIGNAL_FOREIGN_WINDOW_REMOVED "foreign-window-removed"
#define DIYA_SIGNAL_SESSION_LOCKED "session-locked"
#define DIYA_SIGNAL_SESSION_UNLOCKED "session-unlocked"
#define DIYA_PROP_SESSION_LAUNCHPAD "launchpad"
#define DIYA_PROP_SESSION_BACKGROUND "background"
#define DIYA_PROP_SESSION_LOCK "session-lock"
#define DIYA_PROP_SESSION_WINDOWS "windows"
#define DIYA_TYPE_SESSION_SHELL (diya_session_shell_get_type ()) #define DIYA_TYPE_SESSION_SHELL (diya_session_shell_get_type ())
G_DECLARE_FINAL_TYPE (DiyaSessionShell, diya_session_shell, DIYA, SESSION_SHELL, DiyaShell) G_DECLARE_FINAL_TYPE (DiyaSessionShell, diya_session_shell, DIYA, SESSION_SHELL, DiyaShell)
#define DIYA_TYPE_FOREIGN_WINDOW (diya_foreign_window_get_type ()) USE_CLASS(DiyaForeignWindow);
G_DECLARE_FINAL_TYPE (DiyaForeignWindow, diya_foreign_window, DIYA, FOREIGN_WINDOW, DiyaShellObject)
DiyaForeignWindow* diya_session_shell_get_window(DiyaSessionShell * shell, gpointer handle); DiyaForeignWindow* diya_session_shell_get_window(DiyaSessionShell * shell, gpointer handle);
gboolean diya_session_shell_add_window(DiyaSessionShell * shell, DiyaForeignWindow * win); gboolean diya_session_shell_add_window(DiyaSessionShell * shell, DiyaForeignWindow * win);
gboolean diya_session_shell_remove_window(DiyaSessionShell * shell, DiyaForeignWindow * win); gboolean diya_session_shell_remove_window(DiyaSessionShell * shell, DiyaForeignWindow * win);
void diya_session_shell_remove_all_windows(DiyaSessionShell * shell); void diya_session_shell_remove_all_windows(DiyaSessionShell * shell);
DiyaSessionShell * diya_session_shell_new(GtkApplication * app);
#endif #endif

View File

@ -1,61 +1,6 @@
#include <glib-unix.h> #include <glib-unix.h>
#include <assert.h> #include <assert.h>
#include "shell.h" #include "session-shell.h"
#include "background.h"
#include "launcher.h"
#include "wayland.h"
#include "foreign.h"
#include "session-lock.h"
static gchar **g_shell_argv;
static void activate(GtkApplication *app, void *data)
{
(void)app;
(void)data;
DiyaSessionShell *shell = data;
diya_session_shell_lock(shell);
}
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)
{
DiyaSessionShell *shell = data;
diya_session_shell_launcher_init(shell);
diya_session_shell_init_background(shell);
diya_shell_wayland_init(DIYA_SHELL(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);
}
static void session_locked(DiyaSessionShell* shell, void* data) static void session_locked(DiyaSessionShell* shell, void* data)
{ {
@ -73,21 +18,8 @@ static void session_unlocked(DiyaSessionShell* shell, void* data)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
g_shell_argv = g_malloc0(sizeof(gchar *) * (argc + 1)); DiyaSessionShell *shell = DIYA_SESSION_SHELL(g_object_new(DIYA_TYPE_SESSION_SHELL, "name","dev.iohub.diya.session-shell", NULL));
for (int i = 0; i < argc; i++) g_signal_connect(shell, DIYA_SIGNAL_SESSION_LOCKED, G_CALLBACK(session_locked), NULL);
{ g_signal_connect(shell, DIYA_SIGNAL_SESSION_UNLOCKED, G_CALLBACK(session_unlocked), NULL);
g_shell_argv[i] = argv[i]; return diya_shell_run(DIYA_SHELL(shell), argc, argv);
}
GtkApplication *app = gtk_application_new("dev.iohub.diya.shell", G_APPLICATION_DEFAULT_FLAGS);
DiyaSessionShell *shell = diya_session_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(shell, "session-locked", G_CALLBACK(session_locked), NULL);
g_signal_connect(shell, "session-unlocked", G_CALLBACK(session_unlocked), NULL);
// 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;
} }

View File

@ -1,95 +1,662 @@
#include <glib-unix.h>
#include "shell.h" #include "shell.h"
#include "wayland.h" #include "wayland.h"
#include "virtual-keyboard.h" #include "virtual-keyboard.h"
#include "files-monior.h"
#include "input.h"
#include "idle.h"
#include "wlr-output-power-management-unstable-v1.h"
#include <wayland-client-protocol.h>
#include <gdk/wayland/gdkwayland.h>
#define DEFAULT_IDLE_TIMEOUT 60*1000 // 1m
#define diya_shell_config_theme(priv) (g_strconcat(g_get_home_dir(), "/.themes/", priv->theme ? priv->theme : "default", "/gtk-4.0/gtk.css", NULL))
#define diya_shell_config_theme_dir(priv) (g_strconcat(g_get_home_dir(), "/.themes/", priv->theme ? priv->theme : "default", "/gtk-4.0", NULL))
enum enum
{ {
NO_PROP, NO_PROP,
PROP_SHELL_WAYLAND, PROP_SHELL_WAYLAND,
PROP_SHELL_APP,
PROP_SHELL_NAME,
PROP_SHELL_THEME,
PROP_SHELL_IDLE_TO,
N_PROPERTIES N_PROPERTIES
}; };
static GParamSpec *shell_properties[N_PROPERTIES] = {0}; static GParamSpec *shell_properties[N_PROPERTIES] = {0};
typedef struct _DiyaShellPrivate typedef struct _DiyaShellPrivate
{ {
DiyaObject parent; DiyaObject parent;
DiyaWayland * wayland; DiyaWayland *wayland;
DiyaVirtualKeyboard* vkb; GtkApplication *app;
gchar *name;
GHashTable *vkbs;
GtkCssProvider *css_provider;
DiyaInput *input;
DiyaFilesMonitor *files_watchdog;
gchar *theme;
DiyaIdleNotification *idle_notif;
} DiyaShellPrivate; } DiyaShellPrivate;
G_DEFINE_TYPE_WITH_PRIVATE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT); G_DEFINE_TYPE_WITH_PRIVATE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT);
static void diya_shell_finalize(GObject *object)
{
g_debug("diya_shell_finalize: %s", diya_object_to_string(object));
DiyaShell *self = DIYA_SHELL(object);
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
if (priv->name)
{
g_free(priv->name);
priv->name = NULL;
}
if (priv->theme)
{
g_free(priv->theme);
priv->name = NULL;
}
g_hash_table_destroy(priv->vkbs);
G_OBJECT_CLASS(diya_shell_parent_class)->finalize(object);
}
static void diya_shell_dispose(GObject *object)
static void diya_shell_dispose(GObject* object)
{ {
g_debug("diya_shell_dispose: %s", diya_object_to_string(object)); g_debug("diya_shell_dispose: %s", diya_object_to_string(object));
DiyaShell * self = DIYA_SHELL(object); DiyaShell *self = DIYA_SHELL(object);
DiyaShellPrivate* priv = diya_shell_get_instance_private(self); DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
if(priv->wayland) if (priv->wayland)
{ {
g_object_unref(priv->wayland); g_object_unref(priv->wayland);
} }
if (priv->css_provider)
{
g_object_unref(priv->css_provider);
}
if (priv->input)
{
g_object_unref(priv->input);
}
if (priv->files_watchdog)
{
g_object_unref(priv->files_watchdog);
priv->files_watchdog = NULL;
}
if (priv->idle_notif)
{
g_object_unref(priv->idle_notif);
priv->idle_notif = NULL;
}
G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object); G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object);
if (priv->app)
{
g_application_quit(G_APPLICATION(priv->app));
}
}
static void diya_shell_reload_theme(DiyaShell *shell)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
if (priv->css_provider)
{
gtk_style_context_remove_provider_for_display(gdk_display_get_default(), GTK_STYLE_PROVIDER(priv->css_provider));
g_object_unref(priv->css_provider);
priv->css_provider = NULL;
}
priv->css_provider = gtk_css_provider_new();
gchar *css_file = diya_shell_config_theme(priv);
g_debug("diya_shell_reload_theme: Looking for css file: %s", css_file);
if (g_file_test(css_file, G_FILE_TEST_EXISTS))
{
GFile *file = g_file_new_for_path(css_file);
gtk_css_provider_load_from_file(priv->css_provider, file);
g_object_unref(file);
}
else
{
g_warning("diya_shell_reload_theme: Unable to load CSS from file: %s. Fallback to default theme", css_file);
gchar *css_resource = g_strconcat("/dev/iohub/diya/shell/css/", priv->name, ".css", NULL);
gtk_css_provider_load_from_resource(priv->css_provider, css_resource);
g_free(css_resource);
}
g_free(css_file);
gtk_style_context_add_provider_for_display(
gdk_display_get_default(),
GTK_STYLE_PROVIDER(priv->css_provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
}
void diya_shell_reload(DiyaShell *self)
{
diya_shell_reload_theme(self);
}
void on_diya_shell_theme_file_changed(GFileMonitor *monitor, GFile *file, GFile *other, GFileMonitorEvent evtype, gpointer user_data)
{
(void)monitor;
DiyaShell *shell = user_data;
char *fpath = g_file_get_path(file);
char *opath = NULL;
g_debug("%s event %x", fpath, evtype);
if (other)
{
opath = g_file_get_path(other);
}
switch (evtype)
{
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_RENAMED:
case G_FILE_MONITOR_EVENT_MOVED_IN:
case G_FILE_MONITOR_EVENT_MOVED_OUT:
// case G_FILE_MONITOR_EVENT_CHANGED:
// case G_FILE_MONITOR_EVENT_CREATED:
diya_shell_reload_theme(shell);
break;
default:
break;
}
if (opath)
{
g_free(opath);
}
g_free(fpath);
}
static void diya_shell_idle(DiyaIdleNotification *notif, DiyaShell *shell)
{
assert(DIYA_IS_IDLE_NOTIFICATION(notif));
g_signal_emit_by_name(shell, DIYA_SIGNAL_SHELL_IDLE);
}
static void diya_shell_resume(DiyaIdleNotification *notif, DiyaShell *shell)
{
assert(DIYA_IS_IDLE_NOTIFICATION(notif));
g_signal_emit_by_name(shell, DIYA_SIGNAL_SHELL_RESUME);
}
static void on_gtk_app_startup(GtkApplication *app, void *data)
{
(void)app;
DiyaShell *shell = data;
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
priv->wayland = diya_wayland_new(DIYA_SHELL(shell));
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
// read envar
const char *default_theme = g_getenv(DIYA_ENV_THEME);
if (default_theme)
{
priv->theme = g_strdup(default_theme);
}
gchar *dir = diya_shell_config_theme_dir(priv);
diya_shell_watch_file(shell, dir, G_CALLBACK(on_diya_shell_theme_file_changed), (gpointer)shell);
g_free(dir);
diya_shell_reload(shell);
if (class->startup_handle)
{
class->startup_handle(shell);
}
if (class->monitor_changed_handle)
{
GListModel *monitor_list = gdk_display_get_monitors(gdk_display_get_default());
g_debug("listen to monitor changed");
g_signal_connect(monitor_list, "items-changed", G_CALLBACK(class->monitor_changed_handle), shell);
}
}
static void on_gtk_app_active(GtkApplication *app, void *data)
{
(void)app;
DiyaShell *shell = data;
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
// DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
/**
* TODO: read timeout from setting
*/
g_object_set(shell, DIYA_PROP_SHELL_IDLE_TIMEOUT, DEFAULT_IDLE_TIMEOUT, NULL);
if (class->active_handle)
{
class->active_handle(shell);
}
}
static gboolean diya_shell_sigint_handle(gpointer data)
{
g_object_unref(DIYA_SHELL(data));
return true;
}
static gboolean diya_shell_sighub_handle(DiyaShell *self)
{
// reload css file
diya_shell_reload(self);
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(self);
if (class->reload_handle)
{
class->reload_handle(self);
}
return true;
}
static void init_gtk_application(DiyaShell *self)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
if (priv->app)
{
return;
}
priv->app = gtk_application_new(priv->name, G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(priv->app, "startup", G_CALLBACK(on_gtk_app_startup), (void *)self);
g_signal_connect(priv->app, "activate", G_CALLBACK(on_gtk_app_active), (void *)self);
g_unix_signal_add(SIGINT, (GSourceFunc)diya_shell_sigint_handle, (void *)self);
g_unix_signal_add(SIGHUP, (GSourceFunc)diya_shell_sighub_handle, (void *)self);
} }
static void diya_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) static void diya_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{ {
DiyaShell * self = DIYA_SHELL(object); DiyaShell *self = DIYA_SHELL(object);
DiyaShellPrivate* priv = diya_shell_get_instance_private(self); DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
switch (property_id) switch (property_id)
{ {
case PROP_SHELL_WAYLAND: case PROP_SHELL_NAME:
priv->wayland = g_value_get_pointer(value); if (priv->name)
{
return;
}
priv->name = g_strdup(g_value_get_string(value));
init_gtk_application(self);
break; break;
case PROP_SHELL_IDLE_TO:
if(priv->idle_notif)
{
g_object_unref(priv->idle_notif);
}
priv->idle_notif = diya_shell_get_idle_notification(self, g_value_get_uint(value));
g_signal_connect(priv->idle_notif, DIYA_SIGNAL_IDLE_NOTIF_IDLE, G_CALLBACK(diya_shell_idle), self);
g_signal_connect(priv->idle_notif, DIYA_SIGNAL_IDLE_NOTIF_RESUME, G_CALLBACK(diya_shell_resume), self);
break;
case PROP_SHELL_THEME:
{
const gchar *theme = g_value_get_string(value);
if (!priv->theme || !g_str_equal(priv->theme, theme))
{
if (priv->theme)
{
g_free(priv->theme);
}
priv->theme = g_strdup(theme);
diya_shell_reload_theme(self);
}
break;
}
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break; break;
} }
} }
static void diya_shell_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) static void diya_shell_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{ {
DiyaShell * self = DIYA_SHELL(object); DiyaShell *self = DIYA_SHELL(object);
DiyaShellPrivate* priv = diya_shell_get_instance_private(self); DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
switch (property_id) switch (property_id)
{ {
case PROP_SHELL_WAYLAND: case PROP_SHELL_WAYLAND:
g_value_set_pointer(value, priv->wayland); g_value_set_pointer(value, priv->wayland);
break; break;
case PROP_SHELL_APP:
g_value_set_pointer(value, priv->app);
break;
case PROP_SHELL_NAME:
g_value_set_string(value, priv->name);
break;
case PROP_SHELL_THEME:
g_value_set_string(value, priv->theme);
break;
case PROP_SHELL_IDLE_TO:
if(priv->idle_notif)
{
g_value_set_uint(value, diya_idle_notification_get_timeout(priv->idle_notif));
}
else
{
g_value_set_uint(value, 0);
}
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break; break;
} }
} }
static void diya_shell_init(DiyaShell *self) static void diya_shell_init(DiyaShell *self)
{ {
DiyaShellPrivate* priv = diya_shell_get_instance_private(self); DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
priv->wayland = NULL; priv->wayland = NULL;
priv->app = NULL;
priv->name = NULL;
priv->vkbs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
priv->css_provider = NULL;
priv->input = NULL;
priv->files_watchdog = NULL;
priv->theme = NULL;
priv->idle_notif = NULL;
} }
DiyaWayland * diya_shell_get_wayland(DiyaShell* shell) DiyaWayland *diya_shell_get_wayland(DiyaShell *shell)
{ {
DiyaWayland * wayland; DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
g_object_get(shell,"wayland", &wayland, NULL); assert(DIYA_IS_WAYLAND(priv->wayland));
assert(DIYA_IS_WAYLAND(wayland)); return priv->wayland;
return wayland; }
GtkApplication *diya_shell_get_application(DiyaShell *shell)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
assert(GTK_IS_APPLICATION(priv->app));
return priv->app;
}
const char *diya_shell_get_name(DiyaShell *shell)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
return priv->name;
}
static const gchar *diya_shell_to_string(DiyaObject *object)
{
return diya_shell_get_name(DIYA_SHELL(object));
} }
static void diya_shell_class_init(DiyaShellClass *class) static void diya_shell_class_init(DiyaShellClass *class)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS(class); GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_shell_dispose; gobject_class->dispose = diya_shell_dispose;
gobject_class->finalize = diya_shell_finalize;
gobject_class->set_property = diya_shell_set_property; gobject_class->set_property = diya_shell_set_property;
gobject_class->get_property = diya_shell_get_property; gobject_class->get_property = diya_shell_get_property;
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
base_class->to_string = diya_shell_to_string;
class->foreign_register = NULL; class->foreign_register = NULL;
class->virtual_keyboard_register = diya_virtual_keyboard_register; class->virtual_keyboard_register = diya_virtual_keyboard_register;
class->monitor_changed_handle = NULL;
class->startup_handle = NULL;
class->active_handle = NULL;
class->reload_handle = NULL;
shell_properties[PROP_SHELL_WAYLAND] = g_param_spec_pointer("wayland", NULL, "Shell wayland", G_PARAM_READWRITE); // shell_properties[PROP_SHELL_WAYLAND] = g_param_spec_pointer(DIYA_PROP_SHELL_WAYLAND, NULL, "Shell wayland", G_PARAM_READABLE); //
g_object_class_install_properties (gobject_class, N_PROPERTIES, shell_properties); shell_properties[PROP_SHELL_NAME] = g_param_spec_string(DIYA_PROP_SHELL_NAME, NULL, "Shell name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
shell_properties[PROP_SHELL_APP] = g_param_spec_pointer(DIYA_PROP_SHELL_APPLICATION, NULL, "Shell application", G_PARAM_READABLE);
shell_properties[PROP_SHELL_THEME] = g_param_spec_string(DIYA_PROP_SHELL_THEME, NULL, "Shell theme", NULL, G_PARAM_READWRITE);
shell_properties[PROP_SHELL_IDLE_TO] = g_param_spec_uint(DIYA_PROP_SHELL_IDLE_TIMEOUT, NULL, "Shell IDLE timeout", 0, UINT32_MAX ,DEFAULT_IDLE_TIMEOUT, G_PARAM_READWRITE);
g_object_class_install_properties(gobject_class, N_PROPERTIES, shell_properties);
// define signals
g_signal_new(DIYA_SIGNAL_SHELL_KEYBOARD_ENTER,
DIYA_TYPE_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
3,
G_TYPE_POINTER,
G_TYPE_POINTER,
G_TYPE_POINTER);
g_signal_new(DIYA_SIGNAL_SHELL_KEYBOARD_MODIFIER_CHANGED,
DIYA_TYPE_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
2,
G_TYPE_POINTER,
G_TYPE_POINTER);
g_signal_new(DIYA_SIGNAL_SHELL_KEYBOARD_LEAVE,
DIYA_TYPE_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
g_signal_new(DIYA_SIGNAL_SHELL_KEY_PRESSED,
DIYA_TYPE_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
4,
G_TYPE_POINTER,
G_TYPE_POINTER,
G_TYPE_UINT,
G_TYPE_UINT);
g_signal_new(DIYA_SIGNAL_SHELL_KEY_RELEASED,
DIYA_TYPE_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
4,
G_TYPE_POINTER,
G_TYPE_POINTER,
G_TYPE_UINT,
G_TYPE_UINT);
g_signal_new(DIYA_SIGNAL_SHELL_IDLE,
DIYA_TYPE_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
g_signal_new(DIYA_SIGNAL_SHELL_RESUME,
DIYA_TYPE_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
}
static int diya_shell_handle_local_options(GApplication *application, GVariantDict *options, gpointer user_data)
{
(void)application;
(void)user_data;
#ifdef __SHELL_VERSION__
guint32 count;
if (g_variant_dict_lookup(options, "version", "b", &count))
{
g_print("Shell version: %s\n", __SHELL_VERSION__);
return EXIT_SUCCESS;
}
#endif
return -1;
}
int diya_shell_run(DiyaShell *shell, int argc, char **argv)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
assert(GTK_IS_APPLICATION(priv->app));
GtkApplication *app = priv->app;
/*
// theme dir
gchar *path = g_strconcat(g_get_user_config_dir(), "/diya/themes/", NULL);
g_mkdir_with_parents((const gchar *)path, 0755);
g_free(path);
*/
// keymap dir
gchar *path = g_strconcat(g_get_user_config_dir(), "/diya/xkb/", NULL);
g_mkdir_with_parents((const gchar *)path, 0755);
g_free(path);
const GOptionEntry cmd_params[] =
{
#ifdef __SHELL_VERSION__
{
.long_name = "version",
.short_name = 'v',
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_NONE,
.arg_data = NULL,
.description = "Show version information",
.arg_description = NULL,
},
#endif
{NULL}};
g_application_add_main_option_entries(G_APPLICATION(app), cmd_params);
g_signal_connect(app, "handle-local-options", G_CALLBACK(diya_shell_handle_local_options), shell);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
DiyaVirtualKeyboard *diya_shell_get_virtual_keyboard(DiyaShell *shell, const gchar *name)
{
DiyaVirtualKeyboard *vkb = NULL;
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
if (name)
{
if (g_hash_table_contains(priv->vkbs, name))
{
g_debug("diya_shell_get_virtual_keyboard: Getting keyboard %s from cache", name);
vkb = g_hash_table_lookup(priv->vkbs, name);
}
else
{
gchar *keymap_file = g_strconcat(g_get_user_config_dir(), "/diya/xkb/", name, ".keymap", NULL);
g_debug("diya_shell_get_virtual_keyboard: Looking for keymap file: %s", keymap_file);
if (g_file_test(keymap_file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))
{
vkb = diya_virtual_keyboard_new(shell, keymap_file);
if (vkb)
{
g_debug("diya_shell_get_virtual_keyboard: add new keyboard %s to cache", name);
g_hash_table_insert(priv->vkbs, (gpointer)g_strdup(name), vkb);
}
}
free(keymap_file);
}
}
if (!vkb)
{
g_debug("Fallback to default virtual key board");
if (!g_hash_table_contains(priv->vkbs, "default"))
{
g_debug("Add new keyboard instance to cache");
g_hash_table_insert(priv->vkbs, (gpointer)g_strdup("default"), diya_virtual_keyboard_new(shell, NULL));
}
vkb = g_hash_table_lookup(priv->vkbs, "default");
}
return vkb;
}
void diya_shell_monitor_input(DiyaShell *self)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
if (priv->input)
{
return;
}
priv->input = diya_input_new(self);
}
gboolean diya_shell_watch_file(DiyaShell *self, const gchar *file, GCallback callback, gpointer userdata)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
if (!priv->files_watchdog)
{
priv->files_watchdog = diya_files_monitor_new();
}
return diya_files_monitor_watch(priv->files_watchdog, file, callback, userdata);
}
void diya_shell_unwatch_file(DiyaShell *self, const gchar *file)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
if (priv->files_watchdog)
{
diya_files_monitor_unwatch(priv->files_watchdog, file);
}
}
void diya_shell_launch(DiyaShell *self, GAppInfo *app)
{
GError *error = NULL;
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
GAppLaunchContext *context = g_app_launch_context_new();
if (priv->theme)
{
g_app_launch_context_setenv(context, "GTK_THEME", priv->theme);
}
g_app_info_launch(app, NULL, context, &error);
g_object_unref(context);
if (error)
{
g_critical("Unable to launch application: %s", error->message);
g_error_free(error);
return;
}
}
void diya_shell_power_display(DiyaShell* self, gboolean mode)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
struct zwlr_output_power_manager_v1 * mngr = diya_wayland_get_output_mngr(priv->wayland);
if(!mngr)
{
g_warning("Output power manager protocol is not available");
return;
}
GdkDisplay *display = gdk_display_get_default();
GListModel *monitors = gdk_display_get_monitors(display);
guint n_monitors = g_list_model_get_n_items(monitors);
for (guint i = 0; i < n_monitors; ++i)
{
GdkMonitor *monitor = g_list_model_get_item(monitors, i);
struct wl_output * output = gdk_wayland_monitor_get_wl_output(monitor);
struct zwlr_output_power_v1 * output_power = zwlr_output_power_manager_v1_get_output_power(mngr, output);
zwlr_output_power_v1_set_mode(output_power, mode? ZWLR_OUTPUT_POWER_V1_MODE_ON: ZWLR_OUTPUT_POWER_V1_MODE_OFF);
zwlr_output_power_v1_destroy(output_power);
}
} }

View File

@ -1,27 +1,57 @@
#ifndef DIYA_SHELL_H #ifndef DIYA_SHELL_H
#define DIYA_SHELL_H #define DIYA_SHELL_H
#include <stdint.h> #include <gio/gio.h>
#include <gtk/gtk.h>
#include "base.h" #include "base.h"
#define DIYA_ENV_THEME "DIYA_DEFAULT_THEME"
#define DIYA_ENV_VKB_KEYMAP "DIYA_VKB_KEYMAP"
#define DIYA_PROP_SHELL_WAYLAND "wayland"
#define DIYA_PROP_SHELL_NAME "name"
#define DIYA_PROP_SHELL_APPLICATION "application"
#define DIYA_PROP_SHELL_THEME "theme"
#define DIYA_PROP_SHELL_IDLE_TIMEOUT "idle-timeout"
#define DIYA_SIGNAL_SHELL_KEYBOARD_ENTER "keyboard-enter"
#define DIYA_SIGNAL_SHELL_KEYBOARD_LEAVE "keyboard-leave"
#define DIYA_SIGNAL_SHELL_KEY_PRESSED "key-pressed"
#define DIYA_SIGNAL_SHELL_KEY_RELEASED "key-released"
#define DIYA_SIGNAL_SHELL_KEYBOARD_MODIFIER_CHANGED "keyboard-modifier-changed"
#define DIYA_SIGNAL_SHELL_IDLE "idle"
#define DIYA_SIGNAL_SHELL_RESUME "resume"
#define DIYA_TYPE_SHELL (diya_shell_get_type()) #define DIYA_TYPE_SHELL (diya_shell_get_type())
G_DECLARE_DERIVABLE_TYPE(DiyaShell, diya_shell, DIYA, SHELL, DiyaObject) G_DECLARE_DERIVABLE_TYPE(DiyaShell, diya_shell, DIYA, SHELL, DiyaObject)
#define DIYA_TYPE_WAYLAND (diya_wayland_get_type ())
G_DECLARE_FINAL_TYPE (DiyaWayland, diya_wayland, DIYA, WAYLAND, DiyaShellObject)
struct wl_registry; struct wl_registry;
typedef void (*wl_protocol_manager_register_t)(struct wl_registry*, uint32_t,DiyaShell*); typedef void (*wl_protocol_manager_register_t)(gpointer,DiyaShell*);
struct _DiyaShellClass struct _DiyaShellClass
{ {
DiyaObjectClass parent_class; DiyaObjectClass parent_class;
wl_protocol_manager_register_t foreign_register; wl_protocol_manager_register_t foreign_register;
wl_protocol_manager_register_t virtual_keyboard_register; wl_protocol_manager_register_t virtual_keyboard_register;
void (*monitor_changed_handle)(GListModel* /*list*/,guint /*position*/, guint /*removed*/,guint /*added*/, gpointer);
void (*startup_handle)(DiyaShell*);
void (*active_handle)(DiyaShell*);
void (*reload_handle)(DiyaShell*);
}; };
void diya_shell_wayland_init(DiyaShell *shell); USE_CLASS(DiyaWayland);
USE_CLASS(DiyaVirtualKeyboard);
DiyaWayland * diya_shell_get_wayland(DiyaShell* shell); DiyaWayland * diya_shell_get_wayland(DiyaShell* shell);
GtkApplication* diya_shell_get_application(DiyaShell* shell);
const char* diya_shell_get_name(DiyaShell* shell);
DiyaVirtualKeyboard* diya_shell_get_virtual_keyboard(DiyaShell* shell, const gchar* name);
void diya_shell_monitor_input(DiyaShell* shell);
gboolean diya_shell_watch_file(DiyaShell* shell, const gchar* file, GCallback callback, gpointer userdata);
void diya_shell_unwatch_file(DiyaShell* shell, const gchar* file);
void diya_shell_power_display(DiyaShell* shell, gboolean mode);
void diya_shell_launch(DiyaShell* shell, GAppInfo* app);
int diya_shell_run(DiyaShell* shell, int argc, char **argv);
#endif #endif

View File

@ -12,24 +12,169 @@
#include "virtual-keyboard-unstable-v1.h" #include "virtual-keyboard-unstable-v1.h"
#include "virtual-keyboard.h" #include "virtual-keyboard.h"
#include "wayland.h" #include "wayland.h"
#include "shell.h"
typedef enum
{
DIYA_VKB_KEY_MOD_NONE = 0,
DIYA_VKB_KEY_MOD_SHIFT = 1,
DIYA_VKB_KEY_MOD_CAPS_LOCK = 2,
DIYA_VKB_KEY_MOD_CTRL = 4,
DIYA_VKB_KEY_MOD_ALT = 8,
DIYA_VKB_KEY_MOD_SUPER = 64,
DIYA_VKB_KEY_MOD_ALT_GR = 128,
} diya_vkb_key_modifier_t;
struct _DiyaVkbKey
{
DiyaObject parent;
uint32_t code;
gchar *key_caps[3];
uint32_t syms[3];
gchar *info;
diya_vkb_key_modifier_t mode;
};
G_DEFINE_FINAL_TYPE(DiyaVkbKey, diya_vkb_key, DIYA_TYPE_OBJECT)
static void diya_vkb_key_finalize(GObject *object)
{
DiyaVkbKey *self = DIYA_VKB_KEY(object);
g_debug("diya_vkb_key_finalize: %s", diya_object_to_string(object));
for (int i = 0; i < 3; i++)
{
if (self->key_caps[i])
{
free(self->key_caps[i]);
}
}
self->code = 0;
if (self->info)
{
free(self->info);
self->info = NULL;
}
G_OBJECT_CLASS(diya_vkb_key_parent_class)->finalize(object);
}
static void diya_vkb_key_dispose(GObject *object)
{
// DiyaVkbKey *self = DIYA_VKB_KEY(object);
g_debug("diya_vkb_key_dispose: %s", diya_object_to_string(object));
G_OBJECT_CLASS(diya_vkb_key_parent_class)->dispose(object);
}
static void diya_vkb_key_init(DiyaVkbKey *self)
{
self->code = 0;
memset(self->key_caps, 0, sizeof(self->key_caps));
memset(self->syms, 0, sizeof(self->syms));
self->mode = DIYA_VKB_KEY_MOD_NONE;
self->info = NULL;
}
static const gchar *diya_vkb_key_to_string(DiyaObject *object)
{
DiyaVkbKey *self = DIYA_VKB_KEY(object);
if (!self->info && self->code != 0)
{
self->info = (char *)malloc(128);
g_snprintf(self->info, 128,
"DiyaVkbKey: %d (0x%.4x: %s, 0x%.4x: %s, 0x%.4x: %s)",
self->code,
self->syms[0],
self->key_caps[0],
self->syms[1],
self->key_caps[1],
self->syms[2],
self->key_caps[2]);
}
return self->info;
}
static void diya_vkb_key_class_init(DiyaVkbKeyClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_vkb_key_dispose;
gobject_class->finalize = diya_vkb_key_finalize;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
base_class->to_string = diya_vkb_key_to_string;
}
const gchar *diya_vkb_key_get_keycap(DiyaVkbKey *key, uint32_t shift_level)
{
if (shift_level > 2)
{
return NULL;
}
return key->key_caps[shift_level];
}
/*uint32_t diya_vkb_key_get_code(DiyaVkbKey *key)
{
return key->code - 8;
}*/
gboolean diya_vkb_key_is_alphabet(DiyaVkbKey* self)
{
return (self->syms[0] >= XKB_KEY_a && self->code <= XKB_KEY_Z);
}
gboolean diya_vkb_key_is_modifier(DiyaVkbKey* self)
{
return self->mode != DIYA_VKB_KEY_MOD_NONE;
}
/**
* @brief DiyaVirtualKeyboard class: lowlevel wayland virtual keyboard handle
*
*/
static struct zwp_virtual_keyboard_manager_v1 *g_virtual_keyboard_manager = NULL;
struct _DiyaVirtualKeyboard struct _DiyaVirtualKeyboard
{ {
DiyaShellObject parent; DiyaShellObject parent;
struct zwp_virtual_keyboard_v1 *keyboard; struct zwp_virtual_keyboard_v1 *keyboard;
struct xkb_context *vkb_ctx;
struct xkb_keymap *vkb_keymap;
GHashTable * keys;
guint32 key_mods;
}; };
G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA_TYPE_SHELL_OBJECT); G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA_TYPE_SHELL_OBJECT);
static void diya_virtual_keyboard_dispose(GObject *object) static void diya_virtual_keyboard_finalize(GObject *object)
{ {
DiyaVirtualKeyboard *self = DIYA_VIRTUAL_KEYBOARD(object); DiyaVirtualKeyboard *self = DIYA_VIRTUAL_KEYBOARD(object);
g_debug("diya_virtual_keyboard_dispose"); g_debug("diya_virtual_keyboard_finalize: %s", diya_object_to_string(object));
g_hash_table_destroy(self->keys);
if (self->keyboard) if (self->keyboard)
{ {
zwp_virtual_keyboard_v1_destroy(self->keyboard); zwp_virtual_keyboard_v1_destroy(self->keyboard);
self->keyboard = NULL;
}
G_OBJECT_CLASS(diya_virtual_keyboard_parent_class)->finalize(object);
}
static void diya_virtual_keyboard_dispose(GObject *object)
{
DiyaVirtualKeyboard *self = DIYA_VIRTUAL_KEYBOARD(object);
g_debug("diya_virtual_keyboard_dispose: %s", diya_object_to_string(object));
if (self->vkb_keymap)
{
xkb_keymap_unref(self->vkb_keymap);
self->vkb_keymap = NULL;
}
if (self->vkb_ctx)
{
xkb_context_unref(self->vkb_ctx);
self->vkb_ctx = NULL;
} }
G_OBJECT_CLASS(diya_virtual_keyboard_parent_class)->dispose(object); G_OBJECT_CLASS(diya_virtual_keyboard_parent_class)->dispose(object);
} }
@ -37,12 +182,20 @@ static void diya_virtual_keyboard_dispose(GObject *object)
static void diya_virtual_keyboard_init(DiyaVirtualKeyboard *self) static void diya_virtual_keyboard_init(DiyaVirtualKeyboard *self)
{ {
self->keyboard = NULL; self->keyboard = NULL;
self->vkb_ctx = NULL;
self->vkb_keymap = NULL;
self->keys = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
self->key_mods = 0;
} }
static const gchar *diya_virtual_keyboard_to_string(DiyaObject *object) static const gchar *diya_virtual_keyboard_to_string(DiyaObject *object)
{ {
(void)object; DiyaVirtualKeyboard* self = DIYA_VIRTUAL_KEYBOARD(object);
return "Diya virtual keyboard instance"; if(self->vkb_keymap)
{
return xkb_keymap_layout_get_name(self->vkb_keymap,0);
}
return NULL;
} }
static void diya_virtual_keyboard_class_init(DiyaVirtualKeyboardClass *class) static void diya_virtual_keyboard_class_init(DiyaVirtualKeyboardClass *class)
@ -51,9 +204,22 @@ static void diya_virtual_keyboard_class_init(DiyaVirtualKeyboardClass *class)
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class); DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_virtual_keyboard_dispose; gobject_class->dispose = diya_virtual_keyboard_dispose;
gobject_class->finalize = diya_virtual_keyboard_finalize;
// gobject_class->set_property = diya_lock_session_set_property; // gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property; // gobject_class->get_property = diya_lock_session_get_property;
base_class->to_string = diya_virtual_keyboard_to_string; base_class->to_string = diya_virtual_keyboard_to_string;
g_signal_new(DIYA_SIGNAL_VKB_MODIFIER_CHANGED,
DIYA_TYPE_VIRTUAL_KEYBOARD,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0,
NULL);
} }
/* /*
@ -134,87 +300,282 @@ static int create_keymap_fd(off_t size)
DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *keymap_file) DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *keymap_file)
{ {
gchar *content = NULL; struct xkb_context *vkb_ctx = NULL;
GError *error = NULL; struct xkb_keymap *vkb_keymap = NULL;
GBytes *bytes = NULL;
gsize len = 0; gsize len = 0;
vkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (keymap_file) if (!vkb_ctx)
{ {
g_file_get_contents(keymap_file, &content, &len, &error); g_critical("diya_virtual_keyboard_new: Failed to create XKB context: %s", strerror(errno));
if (error != NULL)
{
g_critical("diya_virtual_keyboard_new: Unable to read file %s: %s", keymap_file, error->message);
g_error_free(error);
return NULL; return NULL;
} }
if (keymap_file)
{
g_debug("diya_virtual_keyboard_new: Load keymap from file: %s", keymap_file);
FILE *fp = fopen(keymap_file, "r");
if (!fp)
{
g_critical("diya_virtual_keyboard_new: Failed to open file %s: %s", keymap_file, strerror(errno));
xkb_context_unref(vkb_ctx);
return NULL;
}
vkb_keymap = xkb_keymap_new_from_file(vkb_ctx, fp, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(fp);
} }
else else
{ {
g_warning("No keymap file specified.Loading default keymap from resource"); GError *error = NULL;
GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/shell/default.keymap", 0, &error); g_warning("No keymap file specified. Loading default keymap from resource");
GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/shell/vkb/default.keymap", 0, &error);
if (error != NULL) if (error != NULL)
{ {
g_critical("Unable to read keymap file from resource %s", error->message); g_critical("Unable to read keymap file from resource %s", error->message);
g_error_free(error); g_error_free(error);
xkb_context_unref(vkb_ctx);
return NULL; return NULL;
} }
content = (gchar*)g_bytes_get_data(bytes, &len); vkb_keymap = xkb_keymap_new_from_string(vkb_ctx, (gchar *)g_bytes_get_data(bytes, &len), XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
g_bytes_unref(bytes);
}
if (!vkb_keymap)
{
g_critical("diya_virtual_keyboard_new: Unable to load keymap: %s", strerror(errno));
xkb_context_unref(vkb_ctx);
return NULL;
}
char *content = xkb_keymap_get_as_string(vkb_keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
len = strlen(content);
if (!content)
{
g_critical("diya_virtual_keyboard_new: xkb_keymap_get_as_string: %s", strerror(errno));
xkb_keymap_unref(vkb_keymap);
xkb_context_unref(vkb_ctx);
return NULL;
} }
int fd = create_keymap_fd(len); int fd = create_keymap_fd(len);
if (fd == -1) if (fd == -1)
{ {
g_critical("diya_virtual_keyboard_new: create temp file"); g_critical("diya_virtual_keyboard_new: create temp file");
if(bytes) xkb_keymap_unref(vkb_keymap);
{ xkb_context_unref(vkb_ctx);
g_bytes_unref(bytes); free(content);
content = NULL; return NULL;
}
if(content)
{
g_free(content);
}
} }
void *ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); void *ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == (void *)-1) if (ptr == (void *)-1)
{ {
g_critical("diya_virtual_keyboard_new: error mmap: %s", strerror(errno)); g_critical("diya_virtual_keyboard_new: error mmap: %s", strerror(errno));
xkb_keymap_unref(vkb_keymap);
xkb_context_unref(vkb_ctx);
close(fd); close(fd);
if(bytes) free(content);
{ return NULL;
g_bytes_unref(bytes);
content = NULL;
} }
if(content) // g_debug("Using keymap configuration: \n%s", content);
{
g_free(content);
}
}
strcpy((char *)ptr, content); strcpy((char *)ptr, content);
free(content);
DiyaVirtualKeyboard *vkb = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD, "shell", shell, NULL); DiyaVirtualKeyboard *vkb = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD, "shell", shell, NULL);
vkb->vkb_ctx = vkb_ctx;
vkb->vkb_keymap = vkb_keymap;
DiyaWayland *wayland = diya_shell_get_wayland(shell); DiyaWayland *wayland = diya_shell_get_wayland(shell);
struct wl_seat *seat = diya_wayland_get_seat(wayland); struct wl_seat *seat = diya_wayland_get_seat(wayland);
vkb->keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(g_virtual_keyboard_manager, seat); struct zwp_virtual_keyboard_manager_v1* mngr = diya_wayland_get_virtual_keyboard_mngr(wayland);
if(!mngr)
{
return NULL;
}
vkb->keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(mngr, seat);
zwp_virtual_keyboard_v1_keymap(vkb->keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, len); zwp_virtual_keyboard_v1_keymap(vkb->keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, len);
return vkb; return vkb;
} }
void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell) void diya_virtual_keyboard_register(gpointer mngr, DiyaShell *shell)
{ {
(void)shell; (void) shell;
g_virtual_keyboard_manager = wl_registry_bind(registry, name, &zwp_virtual_keyboard_manager_v1_interface, 1); (void) mngr;
} }
void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard *self, uint32_t key, diya_vkb_state_t state) void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard *self, DiyaVkbKey* key, diya_vkb_state_t state)
{ {
guint32 old_mods = self->key_mods;
GDateTime *now = g_date_time_new_now_local(); GDateTime *now = g_date_time_new_now_local();
uint32_t current_time_ms = g_date_time_get_microsecond(now) / 1000; uint32_t current_time_ms = g_date_time_get_microsecond(now) / 1000;
g_date_time_unref(now); g_date_time_unref(now);
zwp_virtual_keyboard_v1_key(self->keyboard, current_time_ms, key, (uint32_t)state); zwp_virtual_keyboard_v1_key(self->keyboard, current_time_ms, key->code - 8, (uint32_t)state);
switch (state)
{
case VKB_KEY_STATE_PRESSED:
switch (key->mode)
{
case DIYA_VKB_KEY_MOD_NONE:
break;
case DIYA_VKB_KEY_MOD_CAPS_LOCK:
self->key_mods = (self->key_mods & DIYA_VKB_KEY_MOD_CAPS_LOCK) ^ key->mode;
zwp_virtual_keyboard_v1_modifiers(self->keyboard,0,0,self->key_mods,0);
break;
default:
self->key_mods ^= key->mode;
zwp_virtual_keyboard_v1_modifiers(self->keyboard,0,self->key_mods,0,0);
break;
}
break;
case VKB_KEY_STATE_RELEASED:
switch (key->mode)
{
case DIYA_VKB_KEY_MOD_NONE:
if(self->key_mods)
{
self->key_mods = self->key_mods & DIYA_VKB_KEY_MOD_CAPS_LOCK;
zwp_virtual_keyboard_v1_modifiers(self->keyboard,0,0,self->key_mods,0);
}
break;
default:
break;
}
break;
}
if(old_mods != self->key_mods)
{
g_signal_emit_by_name(self,DIYA_SIGNAL_VKB_MODIFIER_CHANGED);
}
}
void diya_virtual_keyboard_init_level(DiyaVkbKey* key, const xkb_keysym_t sym, int level)
{
char buf[32];
key->syms[level] = sym;
diya_vkb_key_modifier_t mod = DIYA_VKB_KEY_MOD_NONE;
switch (sym)
{
case XKB_KEY_Escape:
g_snprintf(buf, sizeof(buf), "%s", "Esc");
break;
case XKB_KEY_BackSpace:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Tab:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Return:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Control_L:
g_snprintf(buf, sizeof(buf), "%s", "Ctrl");
mod = DIYA_VKB_KEY_MOD_CTRL;
break;
case XKB_KEY_Shift_L:
g_snprintf(buf, sizeof(buf), "%s", "");
mod = DIYA_VKB_KEY_MOD_SHIFT;
break;
case XKB_KEY_Caps_Lock:
g_snprintf(buf, sizeof(buf), "%s", "");
mod = DIYA_VKB_KEY_MOD_CAPS_LOCK;
break;
case XKB_KEY_Alt_L:
g_snprintf(buf, sizeof(buf), "%s", "");
mod = DIYA_VKB_KEY_MOD_ALT;
break;
case XKB_KEY_Alt_R:
case XKB_KEY_ISO_Level3_Shift:
g_snprintf(buf, sizeof(buf), "%s", "");
mod = DIYA_VKB_KEY_MOD_ALT_GR;
break;
case XKB_KEY_space:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Up:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Down:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Left:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Right:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_function:
g_snprintf(buf, sizeof(buf), "%s", "Fn");
break;
case XKB_KEY_Meta_L:
g_snprintf(buf, sizeof(buf), "%s", "");
break;
case XKB_KEY_Super_L:
g_snprintf(buf, sizeof(buf), "%s", "");
if(level != 0)
{
key->syms[0] = sym;
key->syms[level] = 0;
}
mod = DIYA_VKB_KEY_MOD_SUPER;
break;
case XKB_KEY_dead_circumflex:
g_snprintf(buf, sizeof(buf), "%s", "^");
break;
case XKB_KEY_dead_diaeresis:
g_snprintf(buf, sizeof(buf), "%s", "¨");
break;
default:
if (xkb_keysym_to_utf8(sym, buf, sizeof(buf)) == 0)
{
return;
}
break;
}
if(level == 0)
{
key->mode = mod;
}
if(sym == XKB_KEY_Super_L && level != 0)
{
if(key->key_caps[0])
{
free(key->key_caps[0]);
}
key->key_caps[0] = g_strdup(buf);
}
else
{
key->key_caps[level] = g_strdup(buf);
}
}
DiyaVkbKey *diya_virtual_keyboard_get_key(DiyaVirtualKeyboard *self, uint32_t code)
{
if(!g_hash_table_contains(self->keys, GUINT_TO_POINTER(code)))
{
DiyaVkbKey *key = g_object_new(DIYA_TYPE_VKB_KEY, NULL);
key->code = code;
int n_level = xkb_keymap_num_levels_for_key(self->vkb_keymap, code, 0);
if (n_level > 0)
{
n_level = n_level > 3 ? 3 : n_level;
for (int level = 0; level < n_level; level++)
{
const xkb_keysym_t *syms = NULL;
int n_sym = xkb_keymap_key_get_syms_by_level(self->vkb_keymap, code, 0, level, &syms);
if (n_sym <= 0 || syms[0] == key->syms[0] || syms[0] == key->syms[1])
{
continue;
}
diya_virtual_keyboard_init_level(key, syms[0],level);
}
}
g_hash_table_insert(self->keys, GUINT_TO_POINTER(code), key);
}
return g_hash_table_lookup(self->keys, GUINT_TO_POINTER(code));
}
gboolean diya_virtual_keyboard_key_modifier_is_active(DiyaVirtualKeyboard* vkb, DiyaVkbKey* key)
{
return (key->mode & vkb->key_mods) > 0;
} }

View File

@ -1,7 +1,16 @@
#ifndef DIYA_VIRTUAL_KEYBOARD_H #ifndef DIYA_VIRTUAL_KEYBOARD_H
#define DIYA_VIRTUAL_KEYBOARD_H #define DIYA_VIRTUAL_KEYBOARD_H
#include "shell.h" #include "base.h"
#define DIYA_SIGNAL_VKB_MODIFIER_CHANGED "modifier-changed"
#define DIYA_SIGNAL_VKB_KEY_PRESSED "pressed"
#define DIYA_SIGNAL_VKB_KEY_RELEASED "released"
#define DIYA_TYPE_VIRTUAL_KEYBOARD (diya_virtual_keyboard_get_type ())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA, VIRTUAL_KEYBOARD, DiyaShellObject)
USE_CLASS(DiyaShell);
typedef enum typedef enum
{ {
@ -9,11 +18,17 @@ typedef enum
VKB_KEY_STATE_PRESSED = 1 /*WL_KEYBOARD_KEY_STATE_PRESSED*/, VKB_KEY_STATE_PRESSED = 1 /*WL_KEYBOARD_KEY_STATE_PRESSED*/,
} diya_vkb_state_t; } diya_vkb_state_t;
#define DIYA_TYPE_VIRTUAL_KEYBOARD (diya_virtual_keyboard_get_type ()) #define DIYA_TYPE_VKB_KEY (diya_vkb_key_get_type ())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA, VIRTUAL_KEYBOARD, DiyaShellObject) G_DECLARE_FINAL_TYPE (DiyaVkbKey, diya_vkb_key, DIYA, VKB_KEY, DiyaObject)
const gchar* diya_vkb_key_get_keycap(DiyaVkbKey* key, uint32_t shift_level);
gboolean diya_vkb_key_is_alphabet(DiyaVkbKey* key);
gboolean diya_vkb_key_is_modifier(DiyaVkbKey* key);
DiyaVirtualKeyboard* diya_virtual_keyboard_new(DiyaShell* shell, const gchar* keymap_file); DiyaVirtualKeyboard* diya_virtual_keyboard_new(DiyaShell* shell, const gchar* keymap_file);
void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell); void diya_virtual_keyboard_register(gpointer mngr, DiyaShell *shell);
void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard* vkb, uint32_t key, diya_vkb_state_t state); void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard* vkb, DiyaVkbKey* key, diya_vkb_state_t state);
DiyaVkbKey* diya_virtual_keyboard_get_key(DiyaVirtualKeyboard* vkb, uint32_t key);
gboolean diya_virtual_keyboard_key_modifier_is_active(DiyaVirtualKeyboard* vkb, DiyaVkbKey* key);
#endif #endif

View File

@ -3,8 +3,10 @@
#include <assert.h> #include <assert.h>
#include "wlr-foreign-toplevel-management-unstable-v1.h" #include "wlr-foreign-toplevel-management-unstable-v1.h"
#include "virtual-keyboard-unstable-v1.h" #include "virtual-keyboard-unstable-v1.h"
#include "ext-idle-notify-v1.h"
#include "wlr-output-power-management-unstable-v1.h"
#include "wayland.h" #include "wayland.h"
#include "shell.h"
struct _DiyaWayland struct _DiyaWayland
{ {
@ -12,13 +14,46 @@ struct _DiyaWayland
struct wl_compositor * compositor; struct wl_compositor * compositor;
struct wl_shm * shm; struct wl_shm * shm;
struct wl_seat * seat; struct wl_seat * seat;
// protocol manager
struct zwlr_foreign_toplevel_manager_v1 * foreign_toplevel_mngr;
struct zwp_virtual_keyboard_manager_v1 * virtual_keyboard_mngr;
struct ext_idle_notifier_v1 * idle_notifier_mngr;
struct zwlr_output_power_manager_v1 * zwlr_output_power_manager_v1;
}; };
G_DEFINE_FINAL_TYPE(DiyaWayland, diya_wayland, DIYA_TYPE_SHELL_OBJECT) G_DEFINE_FINAL_TYPE(DiyaWayland, diya_wayland, DIYA_TYPE_SHELL_OBJECT)
static void diya_wayland_finalize(GObject* object)
{
(void) object;
DiyaWayland * self = DIYA_WAYLAND(object);
if(self->foreign_toplevel_mngr)
{
zwlr_foreign_toplevel_manager_v1_destroy(self->foreign_toplevel_mngr);
self->foreign_toplevel_mngr = NULL;
}
if(self->virtual_keyboard_mngr)
{
zwp_virtual_keyboard_manager_v1_destroy(self->virtual_keyboard_mngr);
self->virtual_keyboard_mngr = NULL;
}
if(self->idle_notifier_mngr)
{
ext_idle_notifier_v1_destroy(self->idle_notifier_mngr);
self->idle_notifier_mngr = NULL;
}
if(self->zwlr_output_power_manager_v1)
{
zwlr_output_power_manager_v1_destroy(self->zwlr_output_power_manager_v1);
self->zwlr_output_power_manager_v1 = NULL;
}
g_debug("diya_wayland_finalize: %s", diya_object_to_string(object));
G_OBJECT_CLASS(diya_wayland_parent_class)->finalize(object);
}
static void diya_wayland_dispose(GObject* object) static void diya_wayland_dispose(GObject* object)
{ {
(void) object; (void) object;
//DiyaWayland * self = DIYA_WAYLAND(object); // DiyaWayland * self = DIYA_WAYLAND(object);
g_debug("diya_wayland_dispose: %s", diya_object_to_string(object)); g_debug("diya_wayland_dispose: %s", diya_object_to_string(object));
G_OBJECT_CLASS(diya_wayland_parent_class)->dispose(object); G_OBJECT_CLASS(diya_wayland_parent_class)->dispose(object);
} }
@ -28,6 +63,10 @@ static void diya_wayland_init(DiyaWayland * self)
self->compositor = NULL; self->compositor = NULL;
self->shm = NULL; self->shm = NULL;
self->seat = NULL; self->seat = NULL;
self->foreign_toplevel_mngr = NULL;
self->virtual_keyboard_mngr = NULL;
self->idle_notifier_mngr = NULL;
self->zwlr_output_power_manager_v1 = NULL;
} }
static const gchar* diya_wayland_to_string(DiyaObject* object) static const gchar* diya_wayland_to_string(DiyaObject* object)
@ -42,6 +81,7 @@ static void diya_wayland_class_init(DiyaWaylandClass *class)
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class); DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_wayland_dispose; gobject_class->dispose = diya_wayland_dispose;
gobject_class->finalize = diya_wayland_finalize;
//gobject_class->set_property = diya_lock_session_set_property; //gobject_class->set_property = diya_lock_session_set_property;
//gobject_class->get_property = diya_lock_session_get_property; //gobject_class->get_property = diya_lock_session_get_property;
base_class->to_string = diya_wayland_to_string; base_class->to_string = diya_wayland_to_string;
@ -60,29 +100,32 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
foreign_toplevel_register(registry,name); foreign_toplevel_register(registry,name);
*/ */
(void) version; (void) version;
DiyaShell * shell = data; DiyaWayland *wayland = data;
DiyaShellClass * class = DIYA_SHELL_GET_CLASS(shell); DiyaShell * shell = diya_shell_object_get_shell(data);
DiyaWayland * wayland;
g_object_get(shell, "wayland", &wayland, NULL);
assert(DIYA_IS_WAYLAND(wayland));
g_debug("WAYLAND GLOBAL: %s", interface);
if (g_strcmp0(interface, zwlr_foreign_toplevel_manager_v1_interface.name) == 0) assert(DIYA_IS_WAYLAND(wayland));
assert(DIYA_IS_SHELL(shell));
DiyaShellClass * class = DIYA_SHELL_GET_CLASS(shell);
g_debug("WAYLAND GLOBAL: %s", interface);
if (!wayland->foreign_toplevel_mngr && g_strcmp0(interface, zwlr_foreign_toplevel_manager_v1_interface.name) == 0)
{ {
if(class->foreign_register) if(class->foreign_register)
{ {
//diya_session_shell_foreign_toplevel_register(registry, name, data); //diya_session_shell_foreign_toplevel_register(registry, name, data);
g_debug("Wayland: register shell foreign top level manager"); g_debug("Wayland: register shell foreign top level manager");
class->foreign_register(registry, name, data); wayland->foreign_toplevel_mngr = wl_registry_bind(registry, name, &zwlr_foreign_toplevel_manager_v1_interface, 3);
class->foreign_register(wayland->foreign_toplevel_mngr, shell);
} }
} }
if (g_strcmp0(interface, zwp_virtual_keyboard_manager_v1_interface.name) == 0) if (!wayland->virtual_keyboard_mngr && g_strcmp0(interface, zwp_virtual_keyboard_manager_v1_interface.name) == 0)
{ {
if(class->virtual_keyboard_register) if(class->virtual_keyboard_register)
{ {
//diya_session_shell_foreign_toplevel_register(registry, name, data); //diya_session_shell_foreign_toplevel_register(registry, name, data);
g_debug("Wayland: register virtual keyboard manager"); g_debug("Wayland: register virtual keyboard manager");
class->virtual_keyboard_register(registry, name, data); wayland->virtual_keyboard_mngr = wl_registry_bind(registry, name, &zwp_virtual_keyboard_manager_v1_interface, 1);
class->virtual_keyboard_register(wayland->virtual_keyboard_mngr, shell);
} }
} }
/* /*
@ -91,22 +134,32 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
diya_session_shell_session_lock_register(registry, name); diya_session_shell_session_lock_register(registry, name);
} }
*/ */
else if (strcmp(interface, wl_compositor_interface.name) == 0) else if (!wayland->compositor && g_strcmp0(interface, wl_compositor_interface.name) == 0)
{ {
wayland->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4); wayland->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4);
} }
else if (strcmp(interface, wl_shm_interface.name) == 0) else if (!wayland->shm && g_strcmp0(interface, wl_shm_interface.name) == 0)
{ {
wayland->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); wayland->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} }
else if (strcmp(interface, wl_seat_interface.name) == 0) else if (!wayland->seat && g_strcmp0(interface, wl_seat_interface.name) == 0)
{ {
wayland->seat = wl_registry_bind(registry, name, &wl_seat_interface, 7); wayland->seat = wl_registry_bind(registry, name, &wl_seat_interface, 7);
} }
else if(!wayland->idle_notifier_mngr && g_strcmp0(interface, ext_idle_notifier_v1_interface.name) == 0)
{
g_debug("Wayland: register ext_idle_notifier_v1_interface");
wayland->idle_notifier_mngr = wl_registry_bind(registry, name, &ext_idle_notifier_v1_interface, 1);;
}
else if (!wayland->zwlr_output_power_manager_v1 && g_strcmp0(interface, zwlr_output_power_manager_v1_interface.name) == 0)
{
g_debug("Wayland: register zwlr_output_power_manager_v1_interface");
wayland->zwlr_output_power_manager_v1 = wl_registry_bind(registry, name, &zwlr_output_power_manager_v1_interface, 1);
//class->power_manager_register(wayland->zwlr_output_power_manager_v1, shell);
}
} }
static void handle_global_remove(void *data, struct wl_registry *registry, static void handle_global_remove(void *data, struct wl_registry *registry,uint32_t name)
uint32_t name)
{ {
(void) data; (void) data;
(void) registry; (void) registry;
@ -119,7 +172,7 @@ static const struct wl_registry_listener registry_listener =
.global_remove = handle_global_remove .global_remove = handle_global_remove
}; };
void diya_shell_wayland_init(DiyaShell *shell) DiyaWayland* diya_wayland_new(DiyaShell *shell)
{ {
struct wl_display *display; struct wl_display *display;
struct wl_registry *registry; struct wl_registry *registry;
@ -127,20 +180,19 @@ void diya_shell_wayland_init(DiyaShell *shell)
if (!display) if (!display)
{ {
g_error("Can't get wayland display"); g_error("Can't get wayland display");
return; return NULL;
} }
DiyaWayland * wayland = g_object_new(DIYA_TYPE_WAYLAND, "shell", shell, NULL); 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); registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, (void*)shell); wl_registry_add_listener(registry, &registry_listener, (void*)wayland);
wl_display_roundtrip(display); // wl_display_roundtrip(display);
// wayland_monitor_probe(); // wayland_monitor_probe();
// GdkMonitor *mon = wayland_monitor_get_default(); // GdkMonitor *mon = wayland_monitor_get_default();
// g_info("default output: %s", (gchar *)g_object_get_data(G_OBJECT(mon), "xdg_name")); // g_info("default output: %s", (gchar *)g_object_get_data(G_OBJECT(mon), "xdg_name"));
// wl_display_roundtrip(display); // wl_display_roundtrip(display);
// wl_display_roundtrip(display); //wl_display_roundtrip(display);
return wayland;
} }
struct wl_surface* diya_wayland_create_surface(DiyaWayland * self) struct wl_surface* diya_wayland_create_surface(DiyaWayland * self)
@ -178,3 +230,18 @@ struct wl_seat* diya_wayland_get_seat(DiyaWayland* self)
assert(self->seat); assert(self->seat);
return self->seat; return self->seat;
} }
struct zwp_virtual_keyboard_manager_v1* diya_wayland_get_virtual_keyboard_mngr(DiyaWayland* self)
{
return self->virtual_keyboard_mngr;
}
struct ext_idle_notifier_v1* diya_wayland_get_idle_mngr(DiyaWayland* self)
{
return self->idle_notifier_mngr;
}
struct zwlr_output_power_manager_v1 * diya_wayland_get_output_mngr(DiyaWayland* self)
{
return self->zwlr_output_power_manager_v1;
}

View File

@ -1,10 +1,19 @@
#ifndef DIYA_SHELL_WAYLAND_H #ifndef DIYA_SHELL_WAYLAND_H
#define DIYA_SHELL_WAYLAND_H #define DIYA_SHELL_WAYLAND_H
#include "shell.h" #include "base.h"
USE_CLASS(DiyaShell);
#define DIYA_TYPE_WAYLAND (diya_wayland_get_type ())
G_DECLARE_FINAL_TYPE (DiyaWayland, diya_wayland, DIYA, WAYLAND, DiyaShellObject)
struct wl_surface* diya_wayland_create_surface(DiyaWayland * self); struct wl_surface* diya_wayland_create_surface(DiyaWayland * self);
struct wl_output* diya_wayland_get_output(DiyaWayland * self, int index); 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); struct wl_shm_pool * diya_wayland_create_shm_pool(DiyaWayland * self, int fd, guint size);
struct wl_seat* diya_wayland_get_seat(DiyaWayland* self); struct wl_seat* diya_wayland_get_seat(DiyaWayland* self);
struct zwp_virtual_keyboard_manager_v1* diya_wayland_get_virtual_keyboard_mngr(DiyaWayland* self);
struct ext_idle_notifier_v1* diya_wayland_get_idle_mngr(DiyaWayland* self);
struct zwlr_output_power_manager_v1 * diya_wayland_get_output_mngr(DiyaWayland* self);
DiyaWayland* diya_wayland_new(DiyaShell *shell);
#endif #endif

106
src/widgets/base-widgets.c Normal file
View File

@ -0,0 +1,106 @@
#include "base-widgets.h"
#include "shell.h"
/**
* @brief Implementation of DiyaShellWindow
*
*/
enum
{
SW_NO_PROP,
SW_SHELL,
SW_N_PROPERTIES
};
static GParamSpec *g_sw_prop[SW_N_PROPERTIES] = {0};
typedef struct _DiyaShellWindowPrivate
{
GtkApplicationWindow parent;
DiyaShell * shell;
} DiyaShellWindowPrivate;
G_DEFINE_TYPE_WITH_PRIVATE(DiyaShellWindow, diya_shell_window, GTK_TYPE_APPLICATION_WINDOW)
static void diya_shell_window_dispose(GObject* object)
{
g_debug("diya_shell_window_dispose");
G_OBJECT_CLASS(diya_shell_window_parent_class)->dispose(object);
}
static void diya_shell_window_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
DiyaShellWindow * self = DIYA_SHELL_WINDOW(object);
DiyaShellWindowPrivate* priv = diya_shell_window_get_instance_private(self);
switch (property_id)
{
case SW_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_window_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
DiyaShellWindow * self = DIYA_SHELL_WINDOW(object);
DiyaShellWindowPrivate* priv = diya_shell_window_get_instance_private(self);
switch (property_id)
{
case SW_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_window_init(DiyaShellWindow *self)
{
DiyaShellWindowPrivate* priv = diya_shell_window_get_instance_private(self);
priv->shell = NULL;
}
static void diya_shell_window_class_init(DiyaShellWindowClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_shell_window_dispose;
gobject_class->set_property = diya_shell_window_set_property;
gobject_class->get_property = diya_shell_window_get_property;
class->setup = NULL;
g_sw_prop[SW_SHELL] = g_param_spec_pointer(DIYA_PROP_SHELL, NULL, "Reference to global shell", G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); //
g_object_class_install_properties (gobject_class, SW_N_PROPERTIES, g_sw_prop);
}
DiyaShellWindow* diya_shell_window_new(GType window_type, gpointer data)
{
DiyaShell* shell = data;
assert(shell);
GtkApplication * app;
g_object_get(shell, DIYA_PROP_SHELL_APPLICATION, &app, NULL);
assert(app);
DiyaShellWindow* self = DIYA_SHELL_WINDOW(g_object_new (window_type, "application", app, "shell",shell, NULL));
DiyaShellWindowClass *class = DIYA_SHELL_WINDOW_GET_CLASS(self);
if(class->setup)
{
class->setup(self);
}
return self;
}
gpointer diya_shell_window_get_shell(DiyaShellWindow* self)
{
DiyaShellWindowPrivate* priv = diya_shell_window_get_instance_private(self);
return priv->shell;
}

View File

@ -0,0 +1,18 @@
#ifndef DIYA_BASE_WIDGETS_H
#define DIYA_BASE_WIDGETS_H
#include <glib-object.h>
#include <assert.h>
#include <gtk/gtk.h>
#define DIYA_TYPE_SHELL_WINDOW (diya_shell_window_get_type())
G_DECLARE_DERIVABLE_TYPE(DiyaShellWindow, diya_shell_window, DIYA, SHELL_WINDOW, GtkApplicationWindow)
struct _DiyaShellWindowClass
{
GtkApplicationWindowClass parent_class;
void (*setup)(DiyaShellWindow* self);
};
gpointer diya_shell_window_get_shell(DiyaShellWindow* self);
DiyaShellWindow* diya_shell_window_new(GType window_type, gpointer shell);
#endif

View File

@ -0,0 +1,353 @@
#include "dashboard-widget.h"
/**
* Implementation of list model
*
*/
struct _DiyaDashboardListModel
{
GObject parent_instance;
GList *appinfos;
};
static guint diya_dashboard_list_model_get_n_items(GListModel *list)
{
DiyaDashboardListModel *self = DIYA_DASHBOARD_LIST_MODEL(list);
return g_list_length(self->appinfos);
}
static gpointer diya_dashboard_list_model_get_item(GListModel *list, guint position)
{
DiyaDashboardListModel *self = DIYA_DASHBOARD_LIST_MODEL(list);
if(self->appinfos == NULL)
{
return NULL;
}
if(position >= g_list_length(self->appinfos))
{
return NULL;
}
return g_object_ref(g_list_nth_data(self->appinfos, position));
}
static GType diya_dashboard_list_model_get_item_type(GListModel *list)
{
(void)list; // Unused parameter
return G_TYPE_APP_INFO;
}
static void diya_dashboard_list_model_interface_init(GListModelInterface *iface)
{
iface->get_n_items = diya_dashboard_list_model_get_n_items;
iface->get_item = diya_dashboard_list_model_get_item;
iface->get_item_type = diya_dashboard_list_model_get_item_type;
}
G_DEFINE_TYPE_WITH_CODE(DiyaDashboardListModel, diya_dashboard_list_model, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, diya_dashboard_list_model_interface_init))
static void diya_dashboard_list_model_finalize(GObject *object)
{
g_debug("diya_dashboard_list_model_finalize");
DiyaDashboardListModel *self = DIYA_DASHBOARD_LIST_MODEL(object);
g_list_free_full(self->appinfos, g_object_unref);
G_OBJECT_CLASS(diya_dashboard_list_model_parent_class)->finalize(object);
}
static void diya_dashboard_list_model_dispose(GObject *object)
{
(void)object;
g_debug("diya_dashboard_list_model_dispose");
G_OBJECT_CLASS(diya_dashboard_list_model_parent_class)->dispose(object);
}
static void diya_dashboard_list_model_init(DiyaDashboardListModel *self)
{
self->appinfos = NULL;
}
static void diya_dashboard_list_model_class_init(DiyaDashboardListModelClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->finalize = diya_dashboard_list_model_finalize;
gobject_class->dispose = diya_dashboard_list_model_dispose;
}
void diya_dashboard_list_model_append(DiyaDashboardListModel *self, GAppInfo *info)
{
self->appinfos = g_list_append(self->appinfos, g_object_ref(info));
// self->appinfos = g_list_reverse(self->appinfos);
g_list_model_items_changed(G_LIST_MODEL(self), g_list_length(self->appinfos) - 1, 0, 1);
}
static gint diya_dashboard_app_info_cmp(GAppInfo *a, GAppInfo *b)
{
return !g_app_info_equal(a, b);
}
gboolean diya_dashboard_list_model_contain(DiyaDashboardListModel *self, GAppInfo *info)
{
GList *found = NULL;
found = g_list_find_custom(self->appinfos, info, (GCompareFunc)diya_dashboard_app_info_cmp);
return found != NULL;
}
/**
* Implement of Dashboard widget
*
*/
struct _DiyaDashboardWidget
{
DiyaShellWindow parent;
GtkWidget *revealer;
GtkWidget *search_entry;
GtkWidget *app_list_box;
DiyaDashboardListModel *list_model;
GtkSortListModel *sort_model;
GtkFilterListModel *proxy_model;
GtkSorter *sorter;
GtkFilter *filter;
bool active;
};
enum
{
NO_PROP,
PROP_ACTIVE,
N_PROPERTIES
};
static GParamSpec *g_prop[N_PROPERTIES] = {0};
G_DEFINE_TYPE(DiyaDashboardWidget, diya_dashboard_widget, DIYA_TYPE_SHELL_WINDOW)
static void diya_dashboard_widget_dispose(GObject *object)
{
DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(object);
g_debug("diya_dashboard_widget_dispose");
if (self->proxy_model)
{
g_object_unref(self->proxy_model);
}
// verify if the list model + sorter is also unref
G_OBJECT_CLASS(diya_dashboard_widget_parent_class)->dispose(object);
}
static void diya_dashboard_app_launch(GtkFlowBox *box, GtkFlowBoxChild *child, gpointer user_data)
{
(void)box; // Unused parameter
DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(user_data);
int current_index = gtk_flow_box_child_get_index(child);
if (current_index < 0)
{
g_warning("Invalid child index: %d", current_index);
return;
}
GAppInfo *app = G_APP_INFO(g_list_model_get_item(G_LIST_MODEL(self->proxy_model), current_index));
assert(app);
diya_shell_launch(diya_shell_window_get_shell(DIYA_SHELL_WINDOW(self)), app);
g_object_set(self, DIYA_PROP_DASHBOARD_ACTIVE, false, NULL);
g_object_unref(app);
}
static void diya_dashboard_app_icon_clicked(GtkWidget *widget, gpointer user_data)
{
// relay signal to the GTK_FLOW_BOX_CHILD parent
g_signal_emit_by_name(gtk_widget_get_parent(widget), "activate", user_data);
}
static GtkWidget *diya_dashboard_create_app_icon_widget(void *item, void *user_data)
{
(void)user_data; // Unused parameter
GAppInfo *app_info = G_APP_INFO(item);
const gchar *name = g_app_info_get_display_name(app_info);
GIcon *icon = g_app_info_get_icon(app_info);
GtkWidget *widget = gtk_button_new_with_label(name);
if (icon)
{
g_debug("app_info %s has icon %s", name, g_icon_to_string(icon));
// gtk_button_set_icon_name(GTK_BUTTON(widget), g_icon_to_string(icon));
}
g_signal_connect(widget, "clicked", G_CALLBACK(diya_dashboard_app_icon_clicked), user_data);
return widget;
}
static int diya_dashboard_app_info_sort_cmp(GAppInfo *a, GAppInfo *b, gpointer user_data)
{
(void)user_data; // Unused parameter
const gchar *name_a = g_app_info_get_display_name(a);
const gchar *name_b = g_app_info_get_display_name(b);
return g_strcmp0(name_a, name_b);
}
static gboolean diya_app_info_filter_func(GAppInfo *app_info, gpointer user_data)
{
DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(user_data);
gchar *text = g_utf8_strdown(gtk_editable_get_text(GTK_EDITABLE(self->search_entry)), -1);
if (strlen(text) == 0)
{
g_free(text);
return true;
}
gchar *name = g_utf8_strdown(g_app_info_get_display_name(app_info), -1);
if(!name)
{
g_free(text);
return false;
}
gboolean result = g_str_has_prefix(name, text);
g_free(text);
g_free(name);
return result;
}
static void diya_dashboard_search_text_changed(GtkEntry *entry, DiyaDashboardWidget *self)
{
(void)entry; // Unused parameter
gtk_filter_changed(self->filter, GTK_FILTER_CHANGE_DIFFERENT);
}
static void diya_dashboard_widget_init(DiyaDashboardWidget *self)
{
g_debug("diya_dashboard_widget_init");
gtk_widget_init_template(GTK_WIDGET(self));
self->active = false;
// int layer shell for window
gtk_layer_init_for_window(GTK_WINDOW(self));
// anchor window to all edges
gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_LEFT, true);
gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_RIGHT, true);
gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_TOP, true);
gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_BOTTOM, true);
gtk_layer_set_namespace(GTK_WINDOW(self), "diya-dashboard");
// set margin on window
for (int i = 0; i < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; i++)
gtk_layer_set_margin(GTK_WINDOW(self), i, 0);
gtk_layer_set_layer(GTK_WINDOW(self), GTK_LAYER_SHELL_LAYER_TOP);
// gtk_layer_set_keyboard_mode (GTK_WINDOW(self), GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
// the top launcher shall be exclusive
// gtk_layer_auto_exclusive_zone_enable (GTK_WINDOW(self));
gtk_layer_set_keyboard_mode(GTK_WINDOW(self), GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
// gtk_widget_set_can_focus(GTK_WIDGET(self), true);
// gtk_widget_set_name(GTK_WIDGET(dashboard),NAMESPACE);
// gtk_window_set_default_size(GTK_WINDOW(dashboard), 48, 48);
// event controller
// GtkEventController *event_controller = gtk_event_controller_key_new();
// g_signal_connect(event_controller, "key-pressed", G_CALLBACK(on_diya_dashboard_key_press), self);
// gtk_widget_add_controller(GTK_WIDGET(self), event_controller);
self->list_model = g_object_new(DIYA_TYPE_DASHBOARD_LIST_MODEL, NULL);
self->sorter = GTK_SORTER(gtk_custom_sorter_new((GCompareDataFunc)diya_dashboard_app_info_sort_cmp, NULL, NULL));
self->sort_model = gtk_sort_list_model_new(G_LIST_MODEL(self->list_model), self->sorter);
self->filter = GTK_FILTER(gtk_custom_filter_new((GtkCustomFilterFunc)diya_app_info_filter_func, self, NULL));
self->proxy_model = gtk_filter_list_model_new(G_LIST_MODEL(self->sort_model), self->filter);
gtk_flow_box_bind_model(GTK_FLOW_BOX(self->app_list_box), G_LIST_MODEL(self->proxy_model), diya_dashboard_create_app_icon_widget, self, NULL);
gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(self->app_list_box), GTK_SELECTION_SINGLE);
gtk_flow_box_set_activate_on_single_click(GTK_FLOW_BOX(self->app_list_box), true);
}
static void diya_dashboard_show(DiyaDashboardWidget *self)
{
gtk_window_present(GTK_WINDOW(self));
// gtk_widget_set_visible(GTK_WIDGET(self), true);
gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), true);
gtk_window_set_focus(GTK_WINDOW(self), self->search_entry);
// gtk_widget_grab_focus( GTK_WIDGET(self->search_entry));
GList *apps = g_app_info_get_all();
GList *l;
for (l = apps; l != NULL; l = l->next)
{
GAppInfo *info = l->data;
if (diya_dashboard_list_model_contain(self->list_model, info))
{
continue;
}
g_debug("add AppInfo %s", g_app_info_get_id(info));
diya_dashboard_list_model_append(self->list_model, info);
}
g_list_free_full(apps, g_object_unref);
gtk_sorter_changed(self->sorter, GTK_SORTER_CHANGE_INVERTED);
}
static void diya_dashboard_hide(DiyaDashboardWidget *self)
{
gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), false);
gtk_widget_set_visible(GTK_WIDGET(self), false);
}
static void diya_dashboard_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(object);
switch (property_id)
{
case PROP_ACTIVE:
{
gboolean active = g_value_get_boolean(value);
if (self->active == active)
{
return;
}
self->active = active;
if (self->active)
{
diya_dashboard_show(self);
}
else
{
diya_dashboard_hide(self);
}
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void diya_dashboard_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(object);
switch (property_id)
{
case PROP_ACTIVE:
g_value_set_boolean(value, self->active);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void diya_dashboard_widget_class_init(DiyaDashboardWidgetClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_dashboard_widget_dispose;
gobject_class->set_property = diya_dashboard_set_property;
gobject_class->get_property = diya_dashboard_get_property;
// DiyaShellWindowClass* base_class = DIYA_SHELL_WINDOW_CLASS(class);
// base_class->setup = diya_dashboard_widget_setup;
gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(class), "/dev/iohub/diya/shell/ui/dashboard.ui");
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaDashboardWidget, revealer);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaDashboardWidget, search_entry);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaDashboardWidget, app_list_box);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), diya_dashboard_app_launch);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), diya_dashboard_search_text_changed);
gtk_widget_class_set_css_name(GTK_WIDGET_CLASS(class), "diya-dashboard");
// gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
// gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
g_prop[PROP_ACTIVE] = g_param_spec_boolean(DIYA_PROP_DASHBOARD_ACTIVE, NULL, "Active the dashboard", false, G_PARAM_READWRITE); //
g_object_class_install_properties(gobject_class, N_PROPERTIES, g_prop);
}
gboolean diya_dashboard_is_active(DiyaDashboardWidget *self)
{
return self->active;
}

View File

@ -0,0 +1,17 @@
#ifndef DIYA_DASHBOARD_WIDGET_H
#define DIYA_DASHBOARD_WIDGET_H
#include "session-shell.h"
#include "base-widgets.h"
#define DIYA_PROP_DASHBOARD_ACTIVE "active"
#define DIYA_TYPE_DASHBOARD_WIDGET (diya_dashboard_widget_get_type())
G_DECLARE_FINAL_TYPE (DiyaDashboardWidget, diya_dashboard_widget, DIYA, DASHBOARD_WIDGET, DiyaShellWindow)
#define DIYA_TYPE_DASHBOARD_LIST_MODEL (diya_dashboard_list_model_get_type())
G_DECLARE_FINAL_TYPE (DiyaDashboardListModel, diya_dashboard_list_model, DIYA, DASHBOARD_LIST_MODEL, GObject)
gboolean diya_dashboard_is_active(DiyaDashboardWidget* self);
#endif

View File

@ -0,0 +1,413 @@
#include "taskbar-widget.h"
#include "foreign.h"
#define DEFAULT_APP_ICON_NAME "application-x-executable-symbolic"
/**
* Implementation of list model
*
*/
struct _DiyaTaskbarListModel
{
GObject parent_instance;
GList *apps;
};
static guint diya_taskbar_list_model_get_n_items(GListModel *list)
{
DiyaTaskbarListModel *self = DIYA_TASKBAR_LIST_MODEL(list);
return g_list_length(self->apps);
}
static gpointer diya_taskbar_list_model_get_item(GListModel *list, guint position)
{
DiyaTaskbarListModel *self = DIYA_TASKBAR_LIST_MODEL(list);
if(self->apps == NULL)
{
return NULL;
}
if(position >= g_list_length(self->apps))
{
return NULL;
}
return g_object_ref(g_list_nth_data(self->apps, position));
}
static GType diya_taskbar_list_model_get_item_type(GListModel *list)
{
(void)list; // Unused parameter
return DIYA_TYPE_FOREIGN_WINDOW;
}
static void diya_taskbar_list_model_interface_init(GListModelInterface *iface)
{
iface->get_n_items = diya_taskbar_list_model_get_n_items;
iface->get_item = diya_taskbar_list_model_get_item;
iface->get_item_type = diya_taskbar_list_model_get_item_type;
}
G_DEFINE_TYPE_WITH_CODE(DiyaTaskbarListModel, diya_taskbar_list_model, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, diya_taskbar_list_model_interface_init))
static void diya_taskbar_list_model_finalize(GObject *object)
{
g_debug("diya_taskbar_list_model_finalize");
DiyaTaskbarListModel *self = DIYA_TASKBAR_LIST_MODEL(object);
g_list_free_full(self->apps, g_object_unref);
G_OBJECT_CLASS(diya_taskbar_list_model_parent_class)->finalize(object);
}
static void diya_taskbar_list_model_dispose(GObject *object)
{
(void)object;
g_debug("diya_taskbar_list_model_dispose");
G_OBJECT_CLASS(diya_taskbar_list_model_parent_class)->dispose(object);
}
static void diya_taskbar_list_model_init(DiyaTaskbarListModel *self)
{
self->apps = NULL;
}
static void diya_taskbar_list_model_class_init(DiyaTaskbarListModelClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->finalize = diya_taskbar_list_model_finalize;
gobject_class->dispose = diya_taskbar_list_model_dispose;
}
void diya_taskbar_list_model_append(DiyaTaskbarListModel *self, DiyaForeignWindow *window)
{
self->apps = g_list_append(self->apps, g_object_ref(window));
// self->appinfos = g_list_reverse(self->appinfos);
g_list_model_items_changed(G_LIST_MODEL(self), g_list_length(self->apps) - 1, 0, 1);
}
void diya_taskbar_list_model_remove(DiyaTaskbarListModel *self, DiyaForeignWindow *window)
{
gint index = g_list_index(self->apps, window);
if (index < 0)
{
return;
}
self->apps = g_list_remove(self->apps, window);
g_object_unref(window);
g_list_model_items_changed(G_LIST_MODEL(self), index, 1, 0);
}
gboolean diya_taskbar_list_model_contain(DiyaTaskbarListModel *self, DiyaForeignWindow *info)
{
GList *found = NULL;
found = g_list_find(self->apps, info);
return found != NULL;
}
/**
* Implement of taskbar widget
*
*/
struct _DiyaTaskbarWidget
{
DiyaShellWindow parent;
GtkWidget *btn_toggle;
bool active_dashboard;
GtkWidget *apps_list;
GtkSingleSelection *proxy_model;
DiyaTaskbarListModel *model;
GtkListItemFactory *factory;
guint selection_changed_sig_id;
};
enum
{
NO_PROP,
PROP_SHOW_DASHBOARD,
N_PROPERTIES
};
static GParamSpec *g_prop[N_PROPERTIES] = {0};
G_DEFINE_TYPE(DiyaTaskbarWidget, diya_taskbar_widget, DIYA_TYPE_SHELL_WINDOW)
static void diya_taskbar_widget_dispose(GObject *object)
{
DiyaTaskbarWidget *self = DIYA_TASKBAR_WIDGET(object);
g_debug("diya_taskbar_widget_dispose");
if (self->proxy_model)
{
g_object_unref(self->proxy_model);
}
if (self->factory)
{
g_object_unref(self->factory);
}
G_OBJECT_CLASS(diya_taskbar_widget_parent_class)->dispose(object);
}
static void diya_taskbar_setup_apps_list_cb(GtkListItemFactory *factory, GtkListItem *list_item)
{
(void) factory;
GtkWidget *image;
image = gtk_image_new();
gtk_image_set_icon_size(GTK_IMAGE(image), GTK_ICON_SIZE_LARGE);
gtk_list_item_set_child(list_item, image);
}
static void diya_taskbar_bind_apps_list_cb(GtkListItemFactory *factory, GtkListItem *list_item)
{
(void) factory;
GtkWidget *image;
DiyaForeignWindow *win;
image = gtk_list_item_get_child(list_item);
win = gtk_list_item_get_item(list_item);
GAppInfo* info = diya_foreign_window_get_app_info(win);
if(info)
{
assert(G_IS_APP_INFO(info));
gtk_image_set_from_gicon(GTK_IMAGE(image), g_app_info_get_icon(info));
g_object_unref(info);
}
else
{
// get default icon from theme
GtkIconTheme* theme = gtk_icon_theme_get_for_display(gdk_display_get_default());
if(gtk_icon_theme_has_icon(theme, DEFAULT_APP_ICON_NAME))
{
gtk_image_set_from_icon_name(GTK_IMAGE(image), DEFAULT_APP_ICON_NAME);
}
else
{
// fallback to default icon in resource
gtk_image_set_from_resource(GTK_IMAGE(image), "/dev/iohub/diya/shell/icons/scalable/gear");
}
}
}
static guint g_list_model_get_item_index(GListModel *model, gpointer item)
{
for(guint i = 0; i < g_list_model_get_n_items(model); i++)
{
if(g_list_model_get_item(model, i) == item)
{
return i;
}
}
return GTK_INVALID_LIST_POSITION;
}
static void on_foreign_window_state_changed(DiyaSessionShell* shell, DiyaForeignWindow* win, enum diya_win_state state, DiyaTaskbarWidget *self)
{
(void) shell;
DiyaForeignWindow *top_level = diya_foreign_window_get_top_level(win);
guint index = g_list_model_get_item_index(G_LIST_MODEL(self->model), top_level);
guint current_index = gtk_single_selection_get_selected(self->proxy_model);
g_debug("Current index %d, selected index %d", current_index, index);
g_signal_handler_block(self->proxy_model, self->selection_changed_sig_id);
if((state & DIYA_WIN_STATE_FOCUS) && !(state & DIYA_WIN_STATE_MINIMIZE))
{
if(index != GTK_INVALID_LIST_POSITION)
{
gtk_selection_model_select_item(GTK_SELECTION_MODEL(self->proxy_model), index, true);
}
}
else
{
// get the widget under the cursor
if(current_index == index)
{
gtk_selection_model_unselect_item(GTK_SELECTION_MODEL(self->proxy_model), current_index);
}
}
g_signal_handler_unblock(self->proxy_model, self->selection_changed_sig_id);
}
static void on_foreign_window_added(DiyaSessionShell *shell, DiyaForeignWindow *win, DiyaTaskbarWidget *self)
{
(void) shell;
g_debug("Window added %s (toplevel %d)", diya_object_to_string(win), diya_foreign_window_is_toplevel(win));
if(!diya_foreign_window_is_toplevel(win))
{
return;
}
if(diya_taskbar_list_model_contain(self->model, win))
{
return;
}
diya_taskbar_list_model_append(self->model, win);
}
static void on_foreign_window_removed(DiyaSessionShell *shell, DiyaForeignWindow *win, DiyaTaskbarWidget *self)
{
(void) shell;
if (!diya_foreign_window_is_toplevel(win))
{
return;
}
if (diya_taskbar_list_model_contain(self->model, win))
{
diya_taskbar_list_model_remove(self->model, win);
}
}
static void diya_taskbar_list_model_selection_changed_cb(GtkSelectionModel *model, guint position, guint n_items, gpointer user_data)
{
(void) n_items;
(void) user_data;
(void) position;
DiyaForeignWindow *win = gtk_single_selection_get_selected_item(GTK_SINGLE_SELECTION(model));
DiyaTaskbarWidget *self = DIYA_TASKBAR_WIDGET(user_data);
if(gtk_selection_model_is_selected(GTK_SELECTION_MODEL(model), position))
{
g_debug("Activating window: %s", diya_object_to_string(win));
enum diya_win_state state = diya_foreign_window_get_state(win);
if(state & DIYA_WIN_STATE_MINIMIZE)
{
diya_foreign_window_set_state(win, DIYA_WIN_STATE_MINIMIZE, false);
}
if(self->active_dashboard)
{
g_object_set(self, DIYA_PROP_TASKBAR_SHOW_DASHBOARD, !self->active_dashboard, NULL);
}
diya_foreign_window_set_state(win, DIYA_WIN_STATE_FOCUS, true);
}
else
{
diya_foreign_window_set_state(win, DIYA_WIN_STATE_MINIMIZE, true);
}
}
static void diya_taskbar_applist_enter(GtkEventControllerFocus *controller, DiyaTaskbarWidget* self)
{
g_debug("diya_taskbar_applist_enter");
}
static void diya_taskbar_applist_leave(GtkEventControllerFocus *controller, DiyaTaskbarWidget* self)
{
g_debug("diya_taskbar_applist_leaver");
}
static void diya_taskbar_widget_init(DiyaTaskbarWidget *self)
{
g_debug("diya_taskbar_widget_init");
gtk_widget_init_template(GTK_WIDGET(self));
self->active_dashboard = false;
// int layer shell for window
gtk_layer_init_for_window(GTK_WINDOW(self));
// anchor window to all edges
gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_LEFT, true);
gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_RIGHT, true);
gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_TOP, false);
gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_BOTTOM, true);
gtk_layer_set_namespace(GTK_WINDOW(self), "diya-taskbar");
// set margin on window
for (int i = 0; i < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; i++)
gtk_layer_set_margin(GTK_WINDOW(self), i, 0);
gtk_layer_set_layer(GTK_WINDOW(self), GTK_LAYER_SHELL_LAYER_TOP);
gtk_layer_set_keyboard_mode(GTK_WINDOW(self), GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
// the top launcher shall be exclusive
gtk_layer_auto_exclusive_zone_enable(GTK_WINDOW(self));
g_object_bind_property(self->btn_toggle, "active", self, DIYA_PROP_TASKBAR_SHOW_DASHBOARD, G_BINDING_BIDIRECTIONAL);
self->factory = gtk_signal_list_item_factory_new();
g_signal_connect(self->factory, "setup", G_CALLBACK(diya_taskbar_setup_apps_list_cb), NULL);
g_signal_connect(self->factory, "bind", G_CALLBACK(diya_taskbar_bind_apps_list_cb), NULL);
// applists
self->model = DIYA_TASKBAR_LIST_MODEL(g_object_new(DIYA_TYPE_TASKBAR_LIST_MODEL, NULL));
self->proxy_model = gtk_single_selection_new (G_LIST_MODEL(self->model));
gtk_single_selection_set_autoselect(self->proxy_model, false);
gtk_single_selection_set_can_unselect(self->proxy_model, true);
gtk_list_view_set_model(GTK_LIST_VIEW(self->apps_list), GTK_SELECTION_MODEL(self->proxy_model));
gtk_list_view_set_factory(GTK_LIST_VIEW(self->apps_list), GTK_LIST_ITEM_FACTORY(self->factory));
// gtk_list_view_set_single_click_activate(GTK_LIST_VIEW(self->apps_list), true);
self->selection_changed_sig_id = g_signal_connect(GTK_SELECTION_MODEL(self->proxy_model), "selection-changed", G_CALLBACK(diya_taskbar_list_model_selection_changed_cb), self);
// event handle
GtkEventController *controller = gtk_event_controller_focus_new();
g_signal_connect(controller, "enter", G_CALLBACK(diya_taskbar_applist_enter), self);
g_signal_connect(controller, "leave", G_CALLBACK(diya_taskbar_applist_leave), self);
gtk_widget_add_controller(GTK_WIDGET(self->apps_list), GTK_EVENT_CONTROLLER(controller));
}
static void diya_taskbar_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
DiyaTaskbarWidget *self = DIYA_TASKBAR_WIDGET(object);
switch (property_id)
{
case PROP_SHOW_DASHBOARD:
self->active_dashboard = g_value_get_boolean(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void diya_taskbar_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
DiyaTaskbarWidget *self = DIYA_TASKBAR_WIDGET(object);
switch (property_id)
{
case PROP_SHOW_DASHBOARD:
g_value_set_boolean(value, self->active_dashboard);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
/*
static void diya_dashboard_toggle(GtkToggleButton* btn, DiyaTaskbarWidget* self)
{
g_warning("TODDLDLDL");
if(gtk_toggle_button_get_active(btn))
{
gtk_layer_set_exclusive_zone(GTK_WINDOW(self), 0);
}
else
{
gtk_layer_auto_exclusive_zone_enable (GTK_WINDOW(self));
}
}
*/
static void diya_taskbar_widget_setup(DiyaShellWindow* win)
{
DiyaTaskbarWidget* self = DIYA_TASKBAR_WIDGET(win);
DiyaSessionShell *shell = DIYA_SESSION_SHELL(diya_shell_window_get_shell(DIYA_SHELL_WINDOW(self)));
g_signal_connect(shell, DIYA_SIGNAL_FOREIGN_WINDOW_ADDED, G_CALLBACK(on_foreign_window_added), self);
g_signal_connect(shell, DIYA_SIGNAL_FOREIGN_WINDOW_STATE_CHANGED, G_CALLBACK(on_foreign_window_state_changed), self);
g_signal_connect(shell, DIYA_SIGNAL_FOREIGN_WINDOW_REMOVED, G_CALLBACK(on_foreign_window_removed), self);
}
static void diya_taskbar_widget_class_init(DiyaTaskbarWidgetClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_taskbar_widget_dispose;
gobject_class->set_property = diya_taskbar_set_property;
gobject_class->get_property = diya_taskbar_get_property;
DiyaShellWindowClass *window_class = DIYA_SHELL_WINDOW_CLASS(class);
window_class->setup = diya_taskbar_widget_setup;
gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(class), "/dev/iohub/diya/shell/ui/taskbar.ui");
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaTaskbarWidget, btn_toggle);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaTaskbarWidget, apps_list);
// gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), diya_dashboard_toggle);
gtk_widget_class_set_css_name(GTK_WIDGET_CLASS(class), "diya-taskbar");
// gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
// gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
g_prop[PROP_SHOW_DASHBOARD] = g_param_spec_boolean(DIYA_PROP_TASKBAR_SHOW_DASHBOARD, NULL, "Show/hide dashboard", false, G_PARAM_READWRITE); //
g_object_class_install_properties(gobject_class, N_PROPERTIES, g_prop);
}

View File

@ -0,0 +1,15 @@
#ifndef DIYA_TASKBAR_WIDGET_H
#define DIYA_TASKBAR_WIDGET_H
#include "session-shell.h"
#include "base-widgets.h"
#define DIYA_PROP_TASKBAR_SHOW_DASHBOARD "show-taskbar"
#define DIYA_TYPE_TASKBAR_WIDGET (diya_taskbar_widget_get_type())
G_DECLARE_FINAL_TYPE (DiyaTaskbarWidget, diya_taskbar_widget, DIYA, TASKBAR_WIDGET, DiyaShellWindow)
#define DIYA_TYPE_TASKBAR_LIST_MODEL (diya_taskbar_list_model_get_type())
G_DECLARE_FINAL_TYPE (DiyaTaskbarListModel, diya_taskbar_list_model, DIYA, TASKBAR_LIST_MODEL, GObject)
#endif

View File

@ -0,0 +1,372 @@
#include "virtual-keyboard-widgets.h"
/**
* @brief DiyaVkbButton: virtual keyboard button
*/
struct _DiyaVkbButton
{
GtkWidget super;
GtkWidget *labels[3];
DiyaVkbKey *key; /*owned by the virtual keyboard*/
gulong mod_sig_id;
};
G_DEFINE_FINAL_TYPE(DiyaVkbButton, diya_vkb_button, GTK_TYPE_WIDGET);
static void diya_vkb_button_dispose(GObject *object)
{
DiyaVkbButton *self = DIYA_VKB_BUTTON(object);
g_debug("diya_vkb_button_dispose");
for (int i = 0; i < 3; i++)
{
g_clear_pointer(&self->labels[i], gtk_widget_unparent);
}
// g_clear_pointer (&demo->label, gtk_widget_unparent);
G_OBJECT_CLASS(diya_vkb_button_parent_class)->dispose(object);
}
static void diya_vkb_button_event(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
{
(void) n_press;
(void) x;
(void) y;
const gchar* evt_name = (gchar*) data;
GtkEventController *controller = GTK_EVENT_CONTROLLER(gesture);
DiyaVkbButton *self = DIYA_VKB_BUTTON(gtk_event_controller_get_widget(controller));
g_signal_emit_by_name(self, evt_name);
}
static void diya_vkb_button_init(DiyaVkbButton *self)
{
gchar class_name[32]; /*diya-vkb-btn-level-%d */
GtkLayoutManager *grid_layout;
self->key = NULL;
grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
// gtk_orientable_set_orientation(GTK_ORIENTABLE(box_layout), GTK_ORIENTATION_VERTICAL);
// gtk_box_layout_set_spacing (GTK_BOX_LAYOUT (box_layout), 3);
gtk_widget_set_can_focus(GTK_WIDGET(self), false);
// init labels
for (int i = 0; i < 3; i++)
{
self->labels[i] = gtk_label_new(NULL);
g_snprintf(class_name, sizeof(class_name), "shift-level-%d", i + 1);
gtk_widget_add_css_class(self->labels[i], class_name);
gtk_widget_set_hexpand(self->labels[i], true);
gtk_widget_set_parent(self->labels[i], GTK_WIDGET(self));
GtkGridLayoutChild *grid_child = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(grid_layout, self->labels[i]));
switch (i)
{
case 0:
/* code */
gtk_grid_layout_child_set_row(grid_child, 0);
gtk_grid_layout_child_set_column(grid_child, 0);
gtk_grid_layout_child_set_column_span(grid_child, 2);
break;
case 1:
gtk_grid_layout_child_set_row(grid_child, 1);
gtk_grid_layout_child_set_column(grid_child, 0);
gtk_widget_set_halign(self->labels[i], GTK_ALIGN_START);
break;
case 2:
gtk_grid_layout_child_set_row(grid_child, 1);
gtk_grid_layout_child_set_column(grid_child, 1);
gtk_widget_set_halign(self->labels[i], GTK_ALIGN_END);
break;
default:
break;
}
}
// event handle
GtkGesture *controller = gtk_gesture_click_new();
g_signal_connect(controller, "pressed", G_CALLBACK(diya_vkb_button_event), DIYA_SIGNAL_VKB_KEY_PRESSED);
g_signal_connect(controller, "released", G_CALLBACK(diya_vkb_button_event), DIYA_SIGNAL_VKB_KEY_RELEASED);
gtk_widget_add_controller(GTK_WIDGET(self), GTK_EVENT_CONTROLLER(controller));
}
static void diya_vkb_button_class_init(DiyaVkbButtonClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_vkb_button_dispose;
gtk_widget_class_set_css_name(GTK_WIDGET_CLASS(class), "diya-vkb-button");
gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT);
}
void diya_vkb_button_set_key(DiyaVkbButton* btn, DiyaVkbKey *key)
{
btn->key = key;
for (uint32_t i = 0; i < 3; i++)
{
if(key)
{
const char *cap = diya_vkb_key_get_keycap(key, i);
if (cap)
{
if (i == 1 && diya_vkb_key_is_alphabet(key))
{
continue;
}
gtk_label_set_text(GTK_LABEL(btn->labels[i]), cap);
}
}
else
{
gtk_label_set_text(GTK_LABEL(btn->labels[i]), NULL);
}
}
}
DiyaVkbButton *diya_vkb_button_new(DiyaVkbKey *key)
{
DiyaVkbButton *btn = DIYA_VKB_BUTTON(g_object_new(DIYA_TYPE_VKB_BUTTON, NULL));
if(key)
{
diya_vkb_button_set_key(btn, key);
}
btn->mod_sig_id = 0;
return btn;
}
/**
* @brief DiyaVirtualKeyboardWidget: Virtual keyboard GTK widget
*
*/
#define VKB_N_CELLS 145
#define VKB_ROW_NUM(i) (i / 29)
#define VKB_COL_NUM(i) (i % 29)
static uint32_t g_vkb_layout[] = {
49, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 51,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 36,
50, 94, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 111, 66,
9, 206, 64, 65, 0, 108, 113, 116, 114};
struct _DiyaVirtualKeyboardWidget
{
GtkWidget super;
/**
* row 0: 00 - 13
* row 1: 14 - 27
* row 2: 28 - 40
* row 3: 41 - 53
* row 4: 54 - 62
*/
GList *buttons;
DiyaVirtualKeyboard *vkb; /*owned by the widget itself*/
};
G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, GTK_TYPE_WIDGET);
static void diya_virtual_keyboard_widget_dispose(GObject *object)
{
DiyaVirtualKeyboardWidget *self = DIYA_VIRTUAL_KEYBOARD_WIDGET(object);
g_debug("diya_virtual_keyboard_widget_dispose");
if (self->buttons)
{
GList *it = NULL;
for (it = self->buttons; it; it = it->next)
{
if (it->data)
{
g_clear_pointer(&it->data, gtk_widget_unparent);
}
}
}
/* if(self->vkb)
{
g_object_unref(self->vkb);
} */
// g_clear_pointer (&demo->label, gtk_widget_unparent);
G_OBJECT_CLASS(diya_virtual_keyboard_widget_parent_class)->dispose(object);
}
static void diya_virtual_keyboard_widget_init(DiyaVirtualKeyboardWidget *self)
{
// gtk_widget_set_size_request(GTK_WIDGET(self), 600, 400);
g_debug("diya_virtual_keyboard_widget_init: Create new widget");
GtkLayoutManager *grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
// gtk_orientable_set_orientation(GTK_ORIENTABLE(grid_layout), GTK_ORIENTATION_VERTICAL);
gtk_grid_layout_set_row_spacing(GTK_GRID_LAYOUT(grid_layout), 2);
gtk_grid_layout_set_column_spacing(GTK_GRID_LAYOUT(grid_layout), 2);
// gtk_grid_layout_set_baseline_row(GTK_GRID_LAYOUT(grid_layout), 4);
// init buttons
self->vkb = NULL;
}
static void diya_virtual_keyboard_widget_class_init(DiyaVirtualKeyboardWidgetClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_virtual_keyboard_widget_dispose;
gtk_widget_class_set_css_name(GTK_WIDGET_CLASS(class), "diya-vkb");
gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT);
g_signal_new(DIYA_SIGNAL_VKB_KEY_PRESSED,
DIYA_TYPE_VKB_BUTTON,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0,
NULL);
g_signal_new(DIYA_SIGNAL_VKB_KEY_RELEASED,
DIYA_TYPE_VKB_BUTTON,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0,
NULL);
}
static void diya_vkb_widget_on_key_pressed(DiyaVkbButton* button, DiyaVirtualKeyboardWidget* self)
{
gtk_widget_add_css_class(GTK_WIDGET(button), "active");
diya_virtual_keyboard_send_key(self->vkb, button->key,VKB_KEY_STATE_PRESSED);
}
static void diya_vkb_widget_on_key_released(DiyaVkbButton* button, DiyaVirtualKeyboardWidget* self)
{
if(!diya_vkb_key_is_modifier(button->key))
{
gtk_widget_remove_css_class(GTK_WIDGET(button), "active");
}
diya_virtual_keyboard_send_key(self->vkb, button->key,VKB_KEY_STATE_RELEASED);
}
static void on_kb_modifier_changed(DiyaVirtualKeyboard* kb, DiyaVkbButton* button)
{
if(!diya_virtual_keyboard_key_modifier_is_active(kb, button->key))
{
gtk_widget_remove_css_class(GTK_WIDGET(button), "active");
}
}
void diya_virtual_keyboard_widget_set_keyboard(DiyaVirtualKeyboardWidget* self, DiyaVirtualKeyboard* keyboard)
{
self->vkb = keyboard;
int index = 0;
if (self->buttons)
{
GList *it = NULL;
for (it = self->buttons; it; it = it->next)
{
if (it->data)
{
DiyaVkbButton* button = it->data;
DiyaVkbKey *key = NULL;
if(button->mod_sig_id > 0)
{
g_signal_handler_disconnect(self->vkb,button->mod_sig_id);
button->mod_sig_id = 0;
}
if(keyboard)
{
key = diya_virtual_keyboard_get_key(self->vkb, g_vkb_layout[index]);
g_debug("set button key: %s", diya_object_to_string(key));
if(diya_vkb_key_is_modifier(key))
{
button->mod_sig_id = g_signal_connect(self->vkb, DIYA_SIGNAL_VKB_MODIFIER_CHANGED, G_CALLBACK(on_kb_modifier_changed), button);
}
}
diya_vkb_button_set_key(button, key);
index++;
}
}
}
}
GtkWidget *diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard* keyboard)
{
DiyaVirtualKeyboardWidget *self = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD_WIDGET, NULL);
GtkLayoutManager *grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
self->vkb = keyboard;
if(self->vkb == NULL)
{
return NULL;
}
for (int i = 0; i < VKB_N_CELLS; i++)
{
gboolean skip = false;
int row = VKB_ROW_NUM(i);
int col = VKB_COL_NUM(i);
switch (row)
{
case 0:
skip = (col % 2 != 0) || (col > 26);
break;
case 1:
skip = (col == 1) || (col == 2) || (col != 0 && col % 2 == 0);
break;
case 2:
skip = (col == 1) || (col == 2) || (col != 0 && col % 2 == 0) || (col > 25);
break;
case 3:
skip = (col > 0 && col < 3) || (col != 0 && col % 2 == 0);
break;
case 4:
skip = (col > 0 && col < 3) || (col == 4) || (col == 6) || (col > 7 && col < 19) || (col > 19 && col % 2 == 0);
break;
default:
break;
}
if (skip)
{
continue;
}
GtkWidget *button = GTK_WIDGET(diya_vkb_button_new(NULL));
self->buttons = g_list_append(self->buttons, button);
gtk_widget_set_parent(button, GTK_WIDGET(self));
gtk_widget_set_hexpand(button, true);
GtkGridLayoutChild *grid_child = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(grid_layout, button));
g_signal_connect(button, "pressed", G_CALLBACK(diya_vkb_widget_on_key_pressed),self);
g_signal_connect(button, "released", G_CALLBACK(diya_vkb_widget_on_key_released),self);
gtk_grid_layout_child_set_row(grid_child, row);
gtk_grid_layout_child_set_column(grid_child, col);
switch (i)
{
case 26:
case 29:
case 58:
case 87:
case 116:
gtk_grid_layout_child_set_column_span(grid_child, 3);
break;
case 83:
gtk_grid_layout_child_set_column_span(grid_child, 4);
break;
/* case 87:
gtk_grid_layout_child_set_column_span(grid_child, 5); */
break;
case 123:
gtk_grid_layout_child_set_column_span(grid_child, 12);
break;
default:
if (i > 0)
gtk_grid_layout_child_set_column_span(grid_child, 2);
break;
}
}
if(keyboard)
{
diya_virtual_keyboard_widget_set_keyboard(self, keyboard);
}
return GTK_WIDGET(self);
}

View File

@ -0,0 +1,20 @@
#ifndef DIYA_VIRTUAL_KEYBOARD_WIDGETS_H
#define DIYA_VIRTUAL_KEYBOARD_WIDGETS_H
#include "shell.h"
#include "virtual-keyboard.h"
#define DIYA_TYPE_VIRTUAL_KEYBOARD_WIDGET (diya_virtual_keyboard_widget_get_type())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, DIYA, VIRTUAL_KEYBOARD_WIDGET, GtkWidget)
GtkWidget* diya_virtual_keyboard_widget_new(DiyaVirtualKeyboard* keyboard);
void diya_virtual_keyboard_widget_set_keyboard(DiyaVirtualKeyboardWidget* widget, DiyaVirtualKeyboard* keyboard);
#define DIYA_TYPE_VKB_BUTTON (diya_vkb_button_get_type())
G_DECLARE_FINAL_TYPE (DiyaVkbButton, diya_vkb_button, DIYA, VKB_BUTTON, GtkWidget)
DiyaVkbButton* diya_vkb_button_new(DiyaVkbKey* key);
void diya_vkb_button_set_key(DiyaVkbButton* btn, DiyaVkbKey *key);
#endif