Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Librem5
calls
Commits
3201c8e6
Commit
3201c8e6
authored
Aug 13, 2019
by
Bob Ham
Browse files
Display call window over the phosh lockscreen
Closes #41
parent
03ede5b5
Changes
11
Hide whitespace changes
Inline
Side-by-side
debian/copyright
View file @
3201c8e6
...
...
@@ -22,3 +22,24 @@ License: GPL-3+
.
On Debian systems, the full text of the GNU General Public License version 3
can be found in the file `/usr/share/common-licenses/GPL-3'.
Files: src/wayland/wlr-layer-shell-unstable-v1.xml
Copytight: Copyright © 2017 Drew DeVault
License: X11
Permission to use, copy, modify, distribute, and sell this software and
its documentation for any purpose is hereby granted without fee, provided
that the above copyright notice appear in all copies and fthat both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of the copyright holders not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission. The copyright holders make
no representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.
.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
meson.build
View file @
3201c8e6
...
...
@@ -24,7 +24,7 @@ project(
'c'
,
version
:
'0.0.1'
,
license
:
'GPLv3+'
,
meson_version
:
'>= 0.4
6
.0'
,
meson_version
:
'>= 0.4
7
.0'
,
default_options
:
[
'warning_level=1'
,
'buildtype=debugoptimized'
,
...
...
meson_options.txt
View file @
3201c8e6
...
...
@@ -5,3 +5,7 @@ option('gtk_doc',
option
(
'tests'
,
type
:
'boolean'
,
value
:
true
,
description
:
'Whether to compile unit tests'
)
option
(
'wayland'
,
type
:
'feature'
,
value
:
'enabled'
,
description
:
'Whether to support Wayland lockscreen interaction'
)
src/calls-call-window.c
View file @
3201c8e6
...
...
@@ -30,6 +30,7 @@
#include
"calls-call-selector-item.h"
#include
"calls-new-call-box.h"
#include
"calls-enumerate.h"
#include
"calls-wayland-config.h"
#include
"util.h"
#include
<glib/gi18n.h>
...
...
@@ -38,6 +39,11 @@
#define HANDY_USE_UNSTABLE_API
#include
<handy.h>
#ifdef CALLS_WAYLAND
#include
<gdk/gdkwayland.h>
#include
"wlr-layer-shell-unstable-v1-client-protocol.h"
#include
"wayland/layersurface.h"
#endif // CALLS_WAYLAND
struct
_CallsCallWindow
{
...
...
@@ -55,6 +61,13 @@ struct _CallsCallWindow
GtkButton
*
show_calls
;
GtkStack
*
call_stack
;
GtkFlowBox
*
call_selector
;
#ifdef CALLS_WAYLAND
gboolean
screensaver_active
;
struct
zwlr_layer_shell_v1
*
layer_shell_iface
;
struct
wl_output
*
output
;
GtkWindow
*
layer_surface
;
#endif // CALLS_WAYLAND
};
G_DEFINE_TYPE
(
CallsCallWindow
,
calls_call_window
,
GTK_TYPE_APPLICATION_WINDOW
);
...
...
@@ -68,11 +81,108 @@ enum {
static
GParamSpec
*
props
[
PROP_LAST_PROP
];
#ifdef CALLS_WAYLAND
static
void
tear_down_layer_surface
(
CallsCallWindow
*
self
)
{
GtkWidget
*
child
;
if
(
!
self
->
layer_surface
)
{
return
;
}
g_debug
(
"Tearing down layer surface"
);
// Remove window content from layer surface
child
=
gtk_bin_get_child
(
GTK_BIN
(
self
->
layer_surface
));
g_object_ref
(
child
);
gtk_container_remove
(
GTK_CONTAINER
(
self
->
layer_surface
),
child
);
// Add to the call window
gtk_container_add
(
GTK_CONTAINER
(
self
),
child
);
g_object_unref
(
child
);
// Destroy layer surface
gtk_widget_destroy
(
GTK_WIDGET
(
self
->
layer_surface
));
self
->
layer_surface
=
NULL
;
}
static
void
set_up_layer_surface
(
CallsCallWindow
*
self
)
{
GtkWidget
*
child
;
if
(
self
->
layer_surface
||
!
self
->
layer_shell_iface
||
!
self
->
output
)
{
return
;
}
g_debug
(
"Setting up layer surface"
);
// Create layer surface
self
->
layer_surface
=
g_object_new
(
PHOSH_TYPE_LAYER_SURFACE
,
"layer-shell"
,
self
->
layer_shell_iface
,
"wl-output"
,
self
->
output
,
"layer"
,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY
,
"namespace"
,
"calls"
,
"anchor"
,
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT
,
NULL
);
g_assert
(
self
->
layer_surface
);
// Remove window content from call window
child
=
gtk_bin_get_child
(
GTK_BIN
(
self
));
g_object_ref
(
child
);
gtk_container_remove
(
GTK_CONTAINER
(
self
),
child
);
// Add to the layer surface
gtk_container_add
(
GTK_CONTAINER
(
self
->
layer_surface
),
child
);
g_object_unref
(
child
);
// Show the layer surface
gtk_window_set_keep_above
(
self
->
layer_surface
,
TRUE
);
gtk_widget_show
(
GTK_WIDGET
(
self
->
layer_surface
));
}
static
void
update_layer_surface
(
CallsCallWindow
*
self
,
guint
calls
)
{
g_debug
(
"Updating layer surface"
);
if
(
calls
==
0
)
{
tear_down_layer_surface
(
self
);
}
else
if
(
self
->
screensaver_active
)
{
set_up_layer_surface
(
self
);
}
}
#endif // CALLS_WAYLAND
static
void
update_visibility
(
CallsCallWindow
*
self
)
{
guint
calls
=
g_list_model_get_n_items
(
G_LIST_MODEL
(
self
->
call_holders
));
#ifdef CALLS_WAYLAND
update_layer_surface
(
self
,
calls
);
#endif // CALLS_WAYLAND
gtk_widget_set_visible
(
GTK_WIDGET
(
self
),
calls
>
0
);
gtk_widget_set_sensitive
(
GTK_WIDGET
(
self
->
show_calls
),
calls
>
1
);
...
...
@@ -347,6 +457,7 @@ set_provider (CallsCallWindow *self, CallsProvider *provider)
g_object_unref
(
params
);
}
static
void
set_property
(
GObject
*
object
,
guint
property_id
,
...
...
@@ -368,6 +479,163 @@ set_property (GObject *object,
}
#ifdef CALLS_WAYLAND
static
void
get_screensaver_active
(
CallsCallWindow
*
self
,
GtkApplication
*
app
)
{
g_object_get
(
app
,
"screensaver-active"
,
&
self
->
screensaver_active
,
NULL
);
}
static
void
notify_screensaver_active_cb
(
CallsCallWindow
*
self
,
GParamSpec
*
pspec
,
GtkApplication
*
app
)
{
get_screensaver_active
(
self
,
app
);
g_debug
(
"Screensaver became %sactive"
,
self
->
screensaver_active
?
""
:
"in"
);
update_visibility
(
self
);
}
static
gboolean
set_up_screensaver
(
CallsCallWindow
*
self
)
{
GtkApplication
*
app
;
gboolean
reg
;
app
=
gtk_window_get_application
(
GTK_WINDOW
(
self
));
g_assert
(
app
!=
NULL
);
g_object_get
(
app
,
"register-session"
,
&
reg
,
NULL
);
if
(
!
reg
)
{
g_warning
(
"Cannot monitor screensaver state because"
" Application is not set to register with session"
);
return
FALSE
;
}
g_signal_connect_swapped
(
app
,
"notify::screensaver-active"
,
G_CALLBACK
(
notify_screensaver_active_cb
),
self
);
get_screensaver_active
(
self
,
app
);
g_debug
(
"Screensaver is %sactive at startup"
,
self
->
screensaver_active
?
""
:
"in"
);
return
TRUE
;
}
static
void
registry_global_cb
(
void
*
data
,
struct
wl_registry
*
registry
,
uint32_t
name
,
const
char
*
interface
,
uint32_t
version
)
{
CallsCallWindow
*
self
=
CALLS_CALL_WINDOW
(
data
);
if
(
strcmp
(
interface
,
zwlr_layer_shell_v1_interface
.
name
)
==
0
)
{
self
->
layer_shell_iface
=
wl_registry_bind
(
registry
,
name
,
&
zwlr_layer_shell_v1_interface
,
version
);
}
else
if
(
strcmp
(
interface
,
"wl_output"
)
==
0
)
{
// FIXME: Deal with more than one output
if
(
!
self
->
output
)
{
self
->
output
=
wl_registry_bind
(
registry
,
name
,
&
wl_output_interface
,
version
);
}
}
}
static
const
struct
wl_registry_listener
registry_listener
=
{
registry_global_cb
,
// FIXME: Add a remove callback
};
static
void
set_up_wayland
(
CallsCallWindow
*
self
)
{
GdkDisplay
*
gdk_display
;
struct
wl_display
*
display
;
struct
wl_registry
*
registry
;
gdk_display
=
gdk_display_get_default
();
g_assert
(
gdk_display
!=
NULL
);
if
(
!
GDK_IS_WAYLAND_DISPLAY
(
gdk_display
))
{
g_debug
(
"GDK display is not a Wayland display"
);
return
;
}
display
=
gdk_wayland_display_get_wl_display
(
gdk_display
);
g_assert
(
display
!=
NULL
);
registry
=
wl_display_get_registry
(
display
);
g_assert
(
registry
!=
NULL
);
wl_registry_add_listener
(
registry
,
&
registry_listener
,
self
);
wl_display_roundtrip
(
display
);
if
(
!
self
->
layer_shell_iface
)
{
g_warning
(
"Wayland display has no layer shell interface"
);
}
if
(
!
self
->
output
)
{
g_warning
(
"Wayland display has no output"
);
}
}
static
void
application_cb
(
CallsCallWindow
*
self
)
{
gboolean
ok
;
ok
=
set_up_screensaver
(
self
);
if
(
ok
)
{
set_up_wayland
(
self
);
}
}
static
void
notify
(
GObject
*
object
,
GParamSpec
*
pspec
)
{
CallsCallWindow
*
self
=
CALLS_CALL_WINDOW
(
object
);
const
gchar
*
name
;
name
=
g_param_spec_get_name
(
pspec
);
if
(
strcmp
(
name
,
"application"
)
==
0
)
{
application_cb
(
self
);
}
return
;
}
#endif // CALLS_WAYLAND
static
void
constructed
(
GObject
*
object
)
{
...
...
@@ -379,6 +647,8 @@ constructed (GObject *object)
(
GtkFlowBoxCreateWidgetFunc
)
call_holders_create_widget_cb
,
NULL
,
NULL
);
update_visibility
(
self
);
parent_class
->
constructed
(
object
);
}
...
...
@@ -389,8 +659,6 @@ calls_call_window_init (CallsCallWindow *self)
gtk_widget_init_template
(
GTK_WIDGET
(
self
));
self
->
call_holders
=
g_list_store_new
(
CALLS_TYPE_CALL_HOLDER
);
update_visibility
(
self
);
}
...
...
@@ -422,6 +690,12 @@ calls_call_window_class_init (CallsCallWindowClass *klass)
object_class
->
constructed
=
constructed
;
object_class
->
dispose
=
dispose
;
#ifdef CALLS_WAYLAND
// The "application" property is not a construction property so we
// have to wait for it to be set before setting up wayland & co.
object_class
->
notify
=
notify
;
#endif // CALLS_WAYLAND
props
[
PROP_PROVIDER
]
=
g_param_spec_object
(
"provider"
,
_
(
"Provider"
),
...
...
src/calls-wayland-config.h
0 → 100644
View file @
3201c8e6
/*
* Copyright (C) 2019 Purism SPC
*
* This file is part of Calls.
*
* Calls is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calls is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Bob Ham <bob.ham@puri.sm>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#ifndef CALLS__WAYLAND_CONFIG_H__
#define CALLS__WAYLAND_CONFIG_H__
#include
"config.h"
#if WL_SCANNER_FOUND
#include
<gdk/gdk.h>
#ifdef GDK_WINDOWING_WAYLAND
#define CALLS_WAYLAND
#endif // GDK_WINDOWING_WAYLAND
#endif // WL_SCANNER_FOUND
#endif
/* CALLS__WAYLAND_CONFIG_H__ */
src/meson.build
View file @
3201c8e6
...
...
@@ -21,9 +21,12 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
subdir
(
'wayland'
)
gnome
=
import
(
'gnome'
)
src_include
=
include_directories
(
'.'
)
calls_includes
=
[
top_include
,
src_include
]
calls_deps
=
[
dependency
(
'gobject-2.0'
),
dependency
(
'gtk+-3.0'
),
...
...
@@ -34,6 +37,11 @@ calls_deps = [ dependency('gobject-2.0'),
dependency
(
'libebook-contacts-1.2'
),
]
if
wl_scanner
.
found
()
calls_includes
+=
include_directories
(
'wayland'
)
calls_deps
+=
dependency
(
'wayland-client'
,
version
:
'>=1.14'
)
endif
calls_sources
=
files
([
'calls-message-source.c'
,
'calls-message-source.h'
,
'calls-call.c'
,
'calls-origin.c'
,
'calls-origin.h'
,
...
...
@@ -60,6 +68,7 @@ calls_sources = files(['calls-message-source.c', 'calls-message-source.h',
calls_config_data
=
config_data
calls_config_data
.
set_quoted
(
'VCS_TAG'
,
'@VCS_TAG@'
)
calls_config_data
.
set10
(
'WL_SCANNER_FOUND'
,
wl_scanner
.
found
())
config_h_in
=
configure_file
(
output
:
'config.h.in'
,
...
...
@@ -84,8 +93,9 @@ calls_resources = gnome.compile_resources(
)
executable
(
'calls'
,
calls_sources
,
calls_enum_sources
,
calls_resources
,
'main.c'
,
calls_sources
,
calls_enum_sources
,
calls_resources
,
wl_proto_sources
,
wayland_sources
,
'main.c'
,
dependencies
:
calls_deps
,
export_dynamic
:
true
,
include_directories
:
include
_directories
(
'..'
)
,
include_directories
:
calls_
include
s
,
install
:
true
)
src/wayland/layersurface.c
0 → 100644
View file @
3201c8e6
/*
* Copyright (C) 2018 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
* Author: Guido Günther <agx@sigxcpu.org>
*/
/*
WARNING: this file is taken directly from phosh, with no modificaions apart from this message. Please update phosh instead of changing this file. Please copy the file back here afterwards, with the same notice.
*/
#define G_LOG_DOMAIN "phosh-layer-surface"
#include
"config.h"
#include
"layersurface.h"
#include
<gdk/gdkwayland.h>
enum
{
PHOSH_LAYER_SURFACE_PROP_0
,
PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL
,
PHOSH_LAYER_SURFACE_PROP_WL_OUTPUT
,
PHOSH_LAYER_SURFACE_PROP_ANCHOR
,
PHOSH_LAYER_SURFACE_PROP_LAYER
,
PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY
,
PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE
,
PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH
,
PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT
,
PHOSH_LAYER_SURFACE_PROP_NAMESPACE
,
PHOSH_LAYER_SURFACE_PROP_LAST_PROP
};
static
GParamSpec
*
props
[
PHOSH_LAYER_SURFACE_PROP_LAST_PROP
];
enum
{
CONFIGURED
,
N_SIGNALS
};
static
guint
signals
[
N_SIGNALS
];
typedef
struct
{
struct
wl_surface
*
wl_surface
;
struct
zwlr_layer_surface_v1
*
layer_surface
;
/* Properties */
guint
anchor
;
guint
layer
;
gboolean
kbd_interactivity
;
gint
exclusive_zone
;
gint
width
,
height
;
gchar
*
namespace
;
struct
zwlr_layer_shell_v1
*
layer_shell
;
struct
wl_output
*
wl_output
;
}
PhoshLayerSurfacePrivate
;
G_DEFINE_TYPE_WITH_PRIVATE
(
PhoshLayerSurface
,
phosh_layer_surface
,
GTK_TYPE_WINDOW
)
static
void
layer_surface_configure
(
void
*
data
,
struct
zwlr_layer_surface_v1
*
surface
,
uint32_t
serial
,
uint32_t
width
,
uint32_t
height
)
{
PhoshLayerSurface
*
self
=
data
;
gtk_window_resize
(
GTK_WINDOW
(
self
),
width
,
height
);
zwlr_layer_surface_v1_ack_configure
(
surface
,
serial
);
g_signal_emit
(
self
,
signals
[
CONFIGURED
],
0
);
}
static
void
layer_surface_closed
(
void
*
data
,
struct
zwlr_layer_surface_v1
*
surface
)
{
PhoshLayerSurface
*
self
=
data
;
PhoshLayerSurfacePrivate
*
priv
=
phosh_layer_surface_get_instance_private
(
self
);
g_return_if_fail
(
priv
->
layer_surface
==
surface
);
zwlr_layer_surface_v1_destroy
(
priv
->
layer_surface
);
priv
->
layer_surface
=
NULL
;
gtk_widget_destroy
(
GTK_WIDGET
(
self
));
}
static
struct
zwlr_layer_surface_v1_listener
layer_surface_listener
=
{
.
configure
=
layer_surface_configure
,
.
closed
=
layer_surface_closed
,
};
static
void
phosh_layer_surface_set_property
(
GObject
*
object
,
guint
property_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
)
{
PhoshLayerSurface
*
self
=
PHOSH_LAYER_SURFACE
(
object
);
PhoshLayerSurfacePrivate
*
priv
=
phosh_layer_surface_get_instance_private
(
self
);
switch
(
property_id
)
{
case
PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL
:
priv
->
layer_shell
=
g_value_get_pointer
(
value
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_WL_OUTPUT
:
priv
->
wl_output
=
g_value_get_pointer
(
value
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_ANCHOR
:
priv
->
anchor
=
g_value_get_uint
(
value
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_LAYER
:
priv
->
layer
=
g_value_get_uint
(
value
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY
:
priv
->
kbd_interactivity
=
g_value_get_boolean
(
value
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE
:
priv
->
exclusive_zone
=
g_value_get_int
(
value
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH
:
priv
->
width
=
g_value_get_uint
(
value
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT
:
priv
->
height
=
g_value_get_uint
(
value
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_NAMESPACE
:
g_free
(
priv
->
namespace
);
priv
->
namespace
=
g_value_dup_string
(
value
);
break
;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
object
,
property_id
,
pspec
);
break
;
}
}
static
void
phosh_layer_surface_get_property
(
GObject
*
object
,
guint
property_id
,
GValue
*
value
,
GParamSpec
*
pspec
)
{
PhoshLayerSurface
*
self
=
PHOSH_LAYER_SURFACE
(
object
);
PhoshLayerSurfacePrivate
*
priv
=
phosh_layer_surface_get_instance_private
(
self
);
switch
(
property_id
)
{
case
PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL
:
g_value_set_pointer
(
value
,
priv
->
layer_shell
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_WL_OUTPUT
:
g_value_set_pointer
(
value
,
priv
->
wl_output
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_ANCHOR
:
g_value_set_uint
(
value
,
priv
->
anchor
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_LAYER
:
g_value_set_uint
(
value
,
priv
->
layer
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY
:
g_value_set_boolean
(
value
,
priv
->
kbd_interactivity
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE
:
g_value_set_boolean
(
value
,
priv
->
exclusive_zone
);
break
;
case
PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH
: