...
 
Commits (75)
===============
Version 3.31.90
===============
Changes in this release:
• A number of improvements to DzlSuggestionEntry to act more like
GtkEntryCompletion. It now uses pointer grabs while the popover
is displayed.
• Styling for the suggestion entry was tweaked to allow themes more
control over styling.
• DzlProgressMenuButton got a fix for improper gvalue accessor usage.
==============
Version 3.30.2
Version 3.31.4
==============
Changes in this release:
Changes in the release:
• Fix build dependency to properly check for gtk+ >= 3.24. This was already
necessary at runtime, as subtle bugs would have occurred with older
releases.
• app-window now uses GtkEventControllerMotion to provide improved tracking
of the app window fullscreen toolbar.
• Shortcut placement was tweaked in menu popover
• Fixes for shift+tab and ctrl+shift+d keyboard shortcuts
• Various build fixes for -Bsymbolic and assertions
• Improvements to documentation
• Improvements to suggestion entry resiliency
• GIR fixes for DzlGraphModel
• Fixes for ctrl+shift+d
• Use GtkPopover for GMenuModel
• Animation improvements
• Various memory leaks were plugged
• Additional Radio API was added
• A new remove-file signal was added to the directory reaper. This is not
efficient as it passes state to the main thread from a worker thread.
It may be optimized in the future
• Various performance improvements
• File transfer progress callback improvements
==============
Version 3.30.1
Version 3.31.1
==============
Changes in this release:
Changes in the release:
• Correctness fixes to DzlListModelFilter
• DzlMenuButton now properly hides empty menu sections
• DzlPrefernces gained API to do simplified table layouts.
• DzlMenuButton hides separators that are not needed.
• Build requires gtk+-3.0 3.24.0.
• Handle changes to fullscreen state by the window-manager.
• Fixes for mouse tracking on fullscreen windows.
• Align menu shortcuts to the right.
• Fixes for shift-tab to move between widgets.
• Add helper for shortcut tooltips.
• Correctness fixes for listmodel filter.
==============
Version 3.30.0
......
......@@ -33,11 +33,17 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
}
dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > list > row .title {
margin-left: 12px;
color: @theme_fg_color;
}
dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > list > row .separator {
margin-left: 12px;
margin-right: 12px;
}
dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > list > row > box {
margin: 4px 8px 4px 8px;
margin: 4px 8px;
}
dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > list > row:last-child {
......
project('libdazzle', 'c',
version: '3.30.2',
version: '3.31.90',
license: 'GPLv3+',
meson_version: '>= 0.40.1',
meson_version: '>= 0.47.2',
default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ],
)
......
......@@ -9,3 +9,8 @@ StackList
StackListCreateWidgetFunc skip=false
.item type="GLib.Object"
GraphModel
.get_iter_first.iter out
.get_iter_last.iter out
.iter_get_value.value out
.iter_next.iter ref
......@@ -168,6 +168,11 @@ _##prefix##_query_action (GActionGroup *group,
GVariant **state_hint, \
GVariant **state) \
{ \
if (enabled) *enabled = FALSE; \
if (parameter_type) *parameter_type = NULL ; \
if (state_type) *state_type = NULL ; \
if (state_hint) *state_hint = NULL ; \
if (state) *state = NULL ; \
for (guint i = 0; i < G_N_ELEMENTS(prefix##_actions); i++) \
{ \
if (g_strcmp0 (name, prefix##_actions[i].name) == 0) \
......
......@@ -22,6 +22,21 @@
#include "dzl-frame-source.h"
/**
* SECTION:dzl-frame-source
* @title: DzlFrameSource
* @short_description: a frame source for objects without frame clocks
*
* If you are working with something that is not a #GtkWidget, getting
* access to a frame-clock is sometimes not possible. This can be used
* as a suitable fallback that approximates a frame-rate.
*
* If you have access to a #GdkFrameClock, in most cases you'll want that
* instead of using this.
*
* Since: 3.32
*/
typedef struct
{
GSource parent;
......@@ -117,18 +132,44 @@ dzl_frame_source_add (guint frames_per_sec,
guint ret;
g_return_val_if_fail (frames_per_sec > 0, 0);
g_return_val_if_fail (frames_per_sec <= 120, 0);
source = g_source_new(&source_funcs, sizeof(DzlFrameSource));
source = g_source_new (&source_funcs, sizeof (DzlFrameSource));
fsource = (DzlFrameSource *)(gpointer)source;
fsource->fps = frames_per_sec;
fsource->frame_count = 0;
fsource->start_time = g_get_monotonic_time () / 1000L;
g_source_set_callback (source, callback, user_data, NULL);
g_source_set_name (source, "DzlFrameSource");
ret = g_source_attach (source, NULL);
g_source_unref (source);
return ret;
}
guint
dzl_frame_source_add_full (gint priority,
guint frames_per_sec,
GSourceFunc callback,
gpointer user_data,
GDestroyNotify notify)
{
DzlFrameSource *fsource;
GSource *source;
guint ret;
g_return_val_if_fail (frames_per_sec > 0, 0);
source = g_source_new (&source_funcs, sizeof (DzlFrameSource));
fsource = (DzlFrameSource *)(gpointer)source;
fsource->fps = frames_per_sec;
fsource->frame_count = 0;
fsource->start_time = g_get_monotonic_time() / 1000;
g_source_set_callback(source, callback, user_data, NULL);
g_source_set_name(source, "DzlFrameSource");
fsource->start_time = g_get_monotonic_time () / 1000L;
g_source_set_callback (source, callback, user_data, notify);
g_source_set_name (source, "DzlFrameSource");
ret = g_source_attach(source, NULL);
g_source_unref(source);
ret = g_source_attach (source, NULL);
g_source_unref (source);
return ret;
}
......@@ -21,11 +21,20 @@
#include <glib.h>
#include "dzl-version-macros.h"
G_BEGIN_DECLS
guint dzl_frame_source_add (guint frames_per_sec,
GSourceFunc callback,
gpointer user_data);
DZL_AVAILABLE_IN_3_32
guint dzl_frame_source_add (guint frames_per_sec,
GSourceFunc callback,
gpointer user_data);
DZL_AVAILABLE_IN_3_32
guint dzl_frame_source_add_full (gint priority,
guint frames_per_sec,
GSourceFunc callback,
gpointer user_data,
GDestroyNotify notify);
G_END_DECLS
......
animation_headers = [
'dzl-animation.h',
'dzl-box-theatric.h',
'dzl-frame-source.h',
]
animation_sources = [
'dzl-animation.c',
'dzl-box-theatric.c',
'dzl-frame-source.c',
]
libdazzle_public_headers += files(animation_headers)
libdazzle_public_sources += files(animation_sources)
libdazzle_private_sources += files('dzl-frame-source.c')
install_headers(animation_headers, subdir: join_paths(libdazzle_header_subdir, 'animation'))
......@@ -41,6 +41,7 @@ G_BEGIN_DECLS
#include "actions/dzl-widget-action-group.h"
#include "animation/dzl-animation.h"
#include "animation/dzl-box-theatric.h"
#include "animation/dzl-frame-source.h"
#include "app/dzl-application.h"
#include "app/dzl-application-window.h"
#include "bindings/dzl-binding-group.h"
......@@ -110,6 +111,7 @@ G_BEGIN_DECLS
#include "shortcuts/dzl-shortcut-simple-label.h"
#include "shortcuts/dzl-shortcut-theme-editor.h"
#include "shortcuts/dzl-shortcut-theme.h"
#include "shortcuts/dzl-shortcut-tooltip.h"
#include "shortcuts/dzl-shortcuts-group.h"
#include "shortcuts/dzl-shortcuts-section.h"
#include "shortcuts/dzl-shortcuts-shortcut.h"
......
......@@ -19,10 +19,6 @@
#ifndef DZL_DEBUG_H
#define DZL_DEBUG_H
#include <glib.h>
G_BEGIN_DECLS
#ifndef DZL_ENABLE_TRACE
# define DZL_ENABLE_TRACE @ENABLE_TRACING@
#endif
......@@ -30,6 +26,14 @@ G_BEGIN_DECLS
# undef DZL_ENABLE_TRACE
#endif
#include <glib.h>
#ifdef DZL_ENABLE_TRACE
# include <execinfo.h>
#endif
G_BEGIN_DECLS
/**
* DZL_LOG_LEVEL_TRACE: (skip)
*/
......@@ -68,6 +72,17 @@ G_BEGIN_DECLS
G_STRFUNC, __LINE__); \
return _r; \
} G_STMT_END
# define DZL_BACKTRACE \
G_STMT_START { \
gpointer btbuf[64]; \
int btbuflen = backtrace (btbuf, G_N_ELEMENTS (btbuf)); \
char **symnames = backtrace_symbols (btbuf, btbuflen); \
for (guint _i = 0; _i < btbuflen; _i++) { \
g_log(G_LOG_DOMAIN, DZL_LOG_LEVEL_TRACE, "TRACE: [%-2d]: %s", \
_i, symnames[_i]); \
} \
free (symnames); \
} G_STMT_END
#else
# define DZL_TODO(_msg)
# define DZL_PROBE
......@@ -76,6 +91,7 @@ G_BEGIN_DECLS
# define DZL_GOTO(_l) goto _l
# define DZL_EXIT return
# define DZL_RETURN(_r) return _r
# define DZL_BACKTRACE G_STMT_START { } G_STMT_END
#endif
G_END_DECLS
......
......@@ -43,6 +43,7 @@
#define DZL_VERSION_3_28 (G_ENCODE_VERSION (3, 28))
#define DZL_VERSION_3_30 (G_ENCODE_VERSION (3, 30))
#define DZL_VERSION_3_32 (G_ENCODE_VERSION (3, 32))
#if (DZL_MINOR_VERSION == 99)
# define DZL_VERSION_CUR_STABLE (G_ENCODE_VERSION (DZL_MAJOR_VERSION + 1, 0))
......@@ -143,4 +144,18 @@
# define DZL_AVAILABLE_IN_3_30 _DZL_EXTERN
#endif
#if DZL_VERSION_MIN_REQUIRED >= DZL_VERSION_3_32
# define DZL_DEPRECATED_IN_3_32 DZL_DEPRECATED
# define DZL_DEPRECATED_IN_3_32_FOR(f) DZL_DEPRECATED_FOR(f)
#else
# define DZL_DEPRECATED_IN_3_32 _DZL_EXTERN
# define DZL_DEPRECATED_IN_3_32_FOR(f) _DZL_EXTERN
#endif
#if DZL_VERSION_MAX_ALLOWED < DZL_VERSION_3_32
# define DZL_AVAILABLE_IN_3_32 DZL_UNAVAILABLE(3, 32)
#else
# define DZL_AVAILABLE_IN_3_32 _DZL_EXTERN
#endif
#endif /* DZL_VERSION_MACROS_H */
......@@ -52,6 +52,51 @@ struct _DzlDirectoryReaper
G_DEFINE_TYPE (DzlDirectoryReaper, dzl_directory_reaper, G_TYPE_OBJECT)
enum {
REMOVE_FILE,
N_SIGNALS
};
static guint signals [N_SIGNALS];
static gboolean
emit_remove_file_from_main_cb (gpointer data)
{
gpointer *pair = data;
g_signal_emit (pair[0], signals [REMOVE_FILE], 0, pair[1]);
g_object_unref (pair[0]);
g_object_unref (pair[1]);
g_slice_free1 (sizeof (gpointer) * 2, pair);
return G_SOURCE_REMOVE;
}
static gboolean
file_delete (DzlDirectoryReaper *self,
GFile *file,
GCancellable *cancellable,
GError **error)
{
gpointer *data = g_slice_alloc (sizeof (gpointer) * 2);
data[0] = g_object_ref (self);
data[1] = g_object_ref (file);
/* XXX:
*
* It would be awesome if we didn't round-trip to the main
* thread for every one of these files. At least group some
* together occasionally.
*/
g_idle_add_full (G_PRIORITY_LOW + 1000,
emit_remove_file_from_main_cb,
data, NULL);
return g_file_delete (file, cancellable, error);
}
static void
clear_pattern (gpointer data)
{
......@@ -89,6 +134,29 @@ dzl_directory_reaper_class_init (DzlDirectoryReaperClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = dzl_directory_reaper_finalize;
/**
* DzlDirectoryReaper::remove-file:
* @self: a #DzlDirectoryReaper
* @file: a #GFile
*
* The "remove-file" signal is emitted for each file that is removed by the
* #DzlDirectoryReaper instance. This may be useful if you want to show the
* user what was processed by the reaper.
*
* Since: 3.32
*/
signals [REMOVE_FILE] =
g_signal_new_class_handler ("remove-file",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
NULL,
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_FILE);
g_signal_set_va_marshaller (signals [REMOVE_FILE],
G_TYPE_FROM_CLASS (klass),
g_cclosure_marshal_VOID__OBJECTv);
}
static void
......@@ -155,9 +223,10 @@ dzl_directory_reaper_new (void)
}
static gboolean
remove_directory_with_children (GFile *file,
GCancellable *cancellable,
GError **error)
remove_directory_with_children (DzlDirectoryReaper *self,
GFile *file,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GFileEnumerator) enumerator = NULL;
g_autoptr(GError) enum_error = NULL;
......@@ -198,11 +267,11 @@ remove_directory_with_children (GFile *file,
if (!g_file_info_get_is_symlink (info) && file_type == G_FILE_TYPE_DIRECTORY)
{
if (!remove_directory_with_children (child, cancellable, error))
if (!remove_directory_with_children (self, child, cancellable, error))
return FALSE;
}
if (!g_file_delete (child, cancellable, error))
if (!file_delete (self, child, cancellable, error))
return FALSE;
}
......@@ -224,6 +293,7 @@ dzl_directory_reaper_execute_worker (GTask *task,
gpointer task_data,
GCancellable *cancellable)
{
DzlDirectoryReaper *self;
GArray *patterns = task_data;
gint64 now = g_get_real_time ();
......@@ -232,6 +302,8 @@ dzl_directory_reaper_execute_worker (GTask *task,
g_assert (patterns != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
self = g_task_get_source_object (task);
for (guint i = 0; i < patterns->len; i++)
{
const Pattern *p = &g_array_index (patterns, Pattern, i);
......@@ -266,7 +338,7 @@ dzl_directory_reaper_execute_worker (GTask *task,
if (v64 < now - p->min_age)
{
if (!g_file_delete (p->file.file, cancellable, &error))
if (!file_delete (self, p->file.file, cancellable, &error))
g_warning ("%s", error->message);
}
......@@ -331,7 +403,7 @@ dzl_directory_reaper_execute_worker (GTask *task,
if (g_file_info_get_is_symlink (info) || file_type != G_FILE_TYPE_DIRECTORY)
{
if (!g_file_delete (file, cancellable, &error))
if (!file_delete (self, file, cancellable, &error))
{
g_warning ("%s", error->message);
g_clear_error (&error);
......@@ -341,8 +413,8 @@ dzl_directory_reaper_execute_worker (GTask *task,
{
g_assert (file_type == G_FILE_TYPE_DIRECTORY);
if (!remove_directory_with_children (file, cancellable, &error) ||
!g_file_delete (file, cancellable, &error))
if (!remove_directory_with_children (self, file, cancellable, &error) ||
!file_delete (self, file, cancellable, &error))
{
g_warning ("%s", error->message);
g_clear_error (&error);
......@@ -416,6 +488,7 @@ dzl_directory_reaper_execute_async (DzlDirectoryReaper *self,
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, dzl_directory_reaper_execute_async);
g_task_set_task_data (task, g_steal_pointer (&copy), (GDestroyNotify)g_array_unref);
g_task_set_priority (task, G_PRIORITY_LOW + 1000);
g_task_run_in_thread (task, dzl_directory_reaper_execute_worker);
}
......
......@@ -244,12 +244,14 @@ dzl_file_transfer_set_flags (DzlFileTransfer *self,
{
DzlFileTransferPrivate *priv = dzl_file_transfer_get_instance_private (self);
DZL_ENTRY;
g_return_if_fail (DZL_IS_FILE_TRANSFER (self));
if (priv->executed)
{
g_warning ("Cannot set flags after executing transfer");
return;
DZL_EXIT;
}
if (priv->flags != flags)
......@@ -257,6 +259,8 @@ dzl_file_transfer_set_flags (DzlFileTransfer *self,
priv->flags = flags;
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_FLAGS]);
}
DZL_EXIT;
}
gdouble
......@@ -279,18 +283,20 @@ file_walk_full (GFile *parent,
FileWalkCallback callback,
gpointer user_data)
{
DZL_ENTRY;
g_assert (!parent || G_IS_FILE (parent));
g_assert (G_IS_FILE_INFO (info));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
g_assert (callback != NULL);
if (g_cancellable_is_cancelled (cancellable))
return;
DZL_EXIT;
callback (parent, info, user_data);
if (g_file_info_get_is_symlink (info))
return;
DZL_EXIT;
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
{
......@@ -299,7 +305,7 @@ file_walk_full (GFile *parent,
const gchar *name = g_file_info_get_name (info);
if (name == NULL)
return;
DZL_EXIT;
child = g_file_get_child (parent, name);
enumerator = g_file_enumerate_children (child, QUERY_ATTRS, QUERY_FLAGS, cancellable, NULL);
......@@ -308,15 +314,18 @@ file_walk_full (GFile *parent,
{
gpointer infoptr;
while (NULL != (infoptr = g_file_enumerator_next_file (enumerator, cancellable, NULL)))
while ((infoptr = g_file_enumerator_next_file (enumerator, cancellable, NULL)))
{
g_autoptr(GFileInfo) grandchild_info = infoptr;
file_walk_full (child, grandchild_info, cancellable, callback, user_data);
}
g_file_enumerator_close (enumerator, cancellable, NULL);
}
}
DZL_EXIT;
}
static void
......@@ -328,6 +337,8 @@ file_walk (GFile *root,
g_autoptr(GFile) parent = NULL;
g_autoptr(GFileInfo) info = NULL;
DZL_ENTRY;
g_assert (G_IS_FILE (root));
g_assert (callback != NULL);
......@@ -338,6 +349,8 @@ file_walk (GFile *root,
info = g_file_query_info (root, QUERY_ATTRS, QUERY_FLAGS, cancellable, NULL);
if (info != NULL)
file_walk_full (parent, info, cancellable, callback, user_data);
DZL_EXIT;
}
static void
......@@ -348,6 +361,8 @@ handle_preflight_cb (GFile *file,
DzlFileTransferStat *stat_buf = user_data;
GFileType file_type;
DZL_ENTRY;
g_assert (G_IS_FILE (file));
g_assert (G_IS_FILE_INFO (child_info));
g_assert (stat_buf != NULL);
......@@ -363,6 +378,8 @@ handle_preflight_cb (GFile *file,
stat_buf->n_files_total++;
stat_buf->n_bytes_total += g_file_info_get_size (child_info);
}
DZL_EXIT;
}
static void
......@@ -372,11 +389,13 @@ handle_preflight (DzlFileTransfer *self,
{
DzlFileTransferPrivate *priv = dzl_file_transfer_get_instance_private (self);
DZL_ENTRY;
g_assert (DZL_IS_FILE_TRANSFER (self));
g_assert (opers != NULL);
if (g_cancellable_is_cancelled (cancellable))
return;
DZL_EXIT;
for (guint i = 0; i < opers->len; i++)
{
......@@ -392,6 +411,8 @@ handle_preflight (DzlFileTransfer *self,
if (oper->error != NULL)
break;
}
DZL_EXIT;
}
static void
......@@ -417,6 +438,8 @@ handle_copy_cb (GFile *file,
Oper *oper = user_data;
GFileType file_type;
DZL_ENTRY;
g_assert (DZL_IS_FILE_TRANSFER (oper->self));
g_assert (G_IS_FILE (oper->src));
g_assert (G_IS_FILE (oper->dst));
......@@ -424,10 +447,10 @@ handle_copy_cb (GFile *file,
g_assert (G_IS_FILE_INFO (child_info));
if (oper->error != NULL)
return;
DZL_EXIT;
if (g_cancellable_is_cancelled (oper->cancellable))
return;
DZL_EXIT;
priv = dzl_file_transfer_get_instance_private (oper->self);
......@@ -435,7 +458,7 @@ handle_copy_cb (GFile *file,
name = g_file_info_get_name (child_info);
if (name == NULL)
return;
DZL_EXIT;
src = g_file_get_child (file, name);
......@@ -485,6 +508,8 @@ handle_copy_cb (GFile *file,
default:
break;
}
DZL_EXIT;
}
static void
......@@ -492,12 +517,14 @@ handle_copy (DzlFileTransfer *self,
GPtrArray *opers,
GCancellable *cancellable)
{
DZL_ENTRY;
g_assert (DZL_IS_FILE_TRANSFER (self));
g_assert (opers != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
if (g_cancellable_is_cancelled (cancellable))
return;
DZL_EXIT;
for (guint i = 0; i < opers->len; i++)
{
......@@ -518,6 +545,8 @@ handle_copy (DzlFileTransfer *self,
break;
}
}
DZL_EXIT;
}
static void
......@@ -527,12 +556,14 @@ handle_removal (DzlFileTransfer *self,
{
g_autoptr(DzlDirectoryReaper) reaper = NULL;
DZL_ENTRY;
g_assert (DZL_IS_FILE_TRANSFER (self));
g_assert (opers != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
if (g_cancellable_is_cancelled (cancellable))
return;
DZL_EXIT;
reaper = dzl_directory_reaper_new ();
......@@ -546,7 +577,7 @@ handle_removal (DzlFileTransfer *self,
/* Don't delete anything if there was a failure */
if (oper->error != NULL)
return;
DZL_EXIT;
if (g_file_query_file_type (oper->src, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) == G_FILE_TYPE_DIRECTORY)
dzl_directory_reaper_add_directory (reaper, oper->src, 0);
......@@ -555,6 +586,22 @@ handle_removal (DzlFileTransfer *self,
}
dzl_directory_reaper_execute (reaper, cancellable, NULL);
DZL_EXIT;
}
static gboolean
dzl_file_transfer_do_notify_progress (gpointer data)
{
DzlFileTransfer *self = data;
DZL_ENTRY;
g_assert (DZL_IS_FILE_TRANSFER (self));
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PROGRESS]);
DZL_RETURN (G_SOURCE_CONTINUE);
}
static void
......@@ -566,6 +613,7 @@ dzl_file_transfer_worker (GTask *task,
DzlFileTransfer *self = source_object;
DzlFileTransferPrivate *priv = dzl_file_transfer_get_instance_private (self);
GPtrArray *opers = task_data;
guint notify_source;
DZL_ENTRY;
......@@ -574,7 +622,11 @@ dzl_file_transfer_worker (GTask *task,
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
g_assert (opers != NULL);
/* TODO: Start GSource for notifies */
notify_source = g_timeout_add_full (G_PRIORITY_LOW,
1000 / 4, /* 4x a second */
dzl_file_transfer_do_notify_progress,
g_object_ref (self),
g_object_unref);
for (guint i = 0; i < opers->len; i++)
{
......@@ -597,13 +649,14 @@ dzl_file_transfer_worker (GTask *task,
if (oper->error != NULL)
{
g_task_return_error (task, g_steal_pointer (&oper->error));
DZL_EXIT;
DZL_GOTO (cleanup);
}
}
g_task_return_boolean (task, TRUE);
/* TODO: Stop GSource for notifies */
cleanup:
g_source_remove (notify_source);
DZL_EXIT;
}
......@@ -628,10 +681,19 @@ dzl_file_transfer_execute (DzlFileTransfer *self,
if (priv->executed)
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_INVAL,
"Transfer can only be executed once.");
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVAL,
"Transfer can only be executed once.");
DZL_RETURN (FALSE);
}
if (priv->opers->len == 0)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVAL,
"Transfer can only be executed once.");
DZL_RETURN (FALSE);
}
......@@ -661,7 +723,7 @@ dzl_file_transfer_execute_async (DzlFileTransfer *self,
g_return_if_fail (DZL_IS_FILE_TRANSFER (self));
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, NULL, NULL);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, dzl_file_transfer_execute);
if (priv->executed)
......@@ -675,6 +737,15 @@ dzl_file_transfer_execute_async (DzlFileTransfer *self,
priv->executed = TRUE;
if (priv->opers->len == 0)
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_INVAL,
"No transfers were provided to execute");
DZL_EXIT;
}
g_task_set_check_cancellable (task, TRUE);
g_task_set_return_on_cancel (task, TRUE);
g_task_set_priority (task, io_priority);
......
......@@ -1736,6 +1736,52 @@ dzl_dock_bin_init_child (DzlDockBin *self,
child->pre_anim_pinned = TRUE;
}
static gboolean
dzl_dock_bin_draw (GtkWidget *widget,
cairo_t *cr)
{
DzlDockBin *self = (DzlDockBin *)widget;
DzlDockBinPrivate *priv = dzl_dock_bin_get_instance_private (self);
const guint draw_order[] = { DZL_DOCK_BIN_CHILD_CENTER,
DZL_DOCK_BIN_CHILD_LEFT,
DZL_DOCK_BIN_CHILD_RIGHT,
DZL_DOCK_BIN_CHILD_TOP,
DZL_DOCK_BIN_CHILD_BOTTOM };
g_assert (DZL_IS_DOCK_BIN (self));
g_assert (cr != NULL);
/* All pinned children, in proper draw order */
for (guint i = 0; i < G_N_ELEMENTS (draw_order); i++)
{
const DzlDockBinChild *child = &priv->children[draw_order[i]];
if (!child->pinned ||
!GTK_IS_WIDGET (child->widget) ||
!gtk_widget_get_visible (child->widget) ||
!gtk_widget_get_child_visible (child->widget))
continue;
gtk_container_propagate_draw (GTK_CONTAINER (self), child->widget, cr);
}
/* All unpinned children, in proper draw order */
for (guint i = 1; i < G_N_ELEMENTS (draw_order); i++)
{
const DzlDockBinChild *child = &priv->children[draw_order[i]];
if (child->pinned ||
!GTK_IS_WIDGET (child->widget) ||
!gtk_widget_get_visible (child->widget) ||
!gtk_widget_get_child_visible (child->widget))
continue;
gtk_container_propagate_draw (GTK_CONTAINER (self), child->widget, cr);
}
return FALSE;
}
static void
dzl_dock_bin_destroy (GtkWidget *widget)
{
......@@ -1884,6 +1930,7 @@ dzl_dock_bin_class_init (DzlDockBinClass *klass)
widget_class->destroy = dzl_dock_bin_destroy;
widget_class->drag_leave = dzl_dock_bin_drag_leave;
widget_class->drag_motion = dzl_dock_bin_drag_motion;
widget_class->draw = dzl_dock_bin_draw;
widget_class->focus = dzl_dock_bin_focus;
widget_class->get_preferred_height = dzl_dock_bin_get_preferred_height;
widget_class->get_preferred_width = dzl_dock_bin_get_preferred_width;
......
......@@ -38,7 +38,7 @@ DZL_AVAILABLE_IN_ALL
DzlPath *dzl_path_bar_get_path (DzlPathBar *self);
DZL_AVAILABLE_IN_ALL
void dzl_path_bar_set_path (DzlPathBar *self,
DzlPath *path);
DzlPath *path);
DZL_AVAILABLE_IN_ALL
void dzl_path_bar_set_selected_index (DzlPathBar *self,
guint index);
......
......@@ -40,6 +40,8 @@ struct _DzlPreferencesGroup
GtkListBoxRow *last_focused;
guint last_focused_tab_backward : 1;
GHashTable *size_groups;
};
G_END_DECLS
......
......@@ -136,6 +136,7 @@ dzl_preferences_group_finalize (GObject *object)
DzlPreferencesGroup *self = (DzlPreferencesGroup *)object;
g_clear_pointer (&self->widgets, g_ptr_array_unref);
g_clear_pointer (&self->size_groups, g_hash_table_unref);
G_OBJECT_CLASS (dzl_preferences_group_parent_class)->finalize (object);
}
......@@ -446,3 +447,35 @@ dzl_preferences_group_refilter (DzlPreferencesGroup *self,
return lookup.matches;
}
/**
* dzl_preferences_group_get_size_group:
* @self: a #DzlPreferencesGroup
*
* Gets a size group that can be used to organize items in
* a group based on columns.
*
* Returns: (not nullable) (transfer none): a #GtkSizeGroup
*/
GtkSizeGroup *
dzl_preferences_group_get_size_group (DzlPreferencesGroup *self,
guint column)
{
GtkSizeGroup *ret;
g_return_val_if_fail (DZL_IS_PREFERENCES_GROUP (self), NULL);
if (self->size_groups == NULL)
self->size_groups = g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
g_object_unref);
if (!(ret = g_hash_table_lookup (self->size_groups, GUINT_TO_POINTER (column))))
{
ret = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
g_hash_table_insert (self->size_groups, GUINT_TO_POINTER (column), ret);
}
return ret;
}
......@@ -33,18 +33,21 @@ DZL_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (DzlPreferencesGroup, dzl_preferences_group, DZL, PREFERENCES_GROUP, GtkBin)
DZL_AVAILABLE_IN_ALL
void dzl_preferences_group_add (DzlPreferencesGroup *self,
GtkWidget *widget);
void dzl_preferences_group_add (DzlPreferencesGroup *self,
GtkWidget *widget);
DZL_AVAILABLE_IN_ALL
const gchar *dzl_preferences_group_get_title (DzlPreferencesGroup *self);
const gchar *dzl_preferences_group_get_title (DzlPreferencesGroup *self);
DZL_AVAILABLE_IN_ALL
gint dzl_preferences_group_get_priority (DzlPreferencesGroup *self);
gint dzl_preferences_group_get_priority (DzlPreferencesGroup *self);
DZL_AVAILABLE_IN_ALL
void dzl_preferences_group_set_map (DzlPreferencesGroup *self,
GHashTable *map);
void dzl_preferences_group_set_map (DzlPreferencesGroup *self,
GHashTable *map);
DZL_AVAILABLE_IN_ALL
guint dzl_preferences_group_refilter (DzlPreferencesGroup *self,
DzlPatternSpec *spec);
guint dzl_preferences_group_refilter (DzlPreferencesGroup *self,
DzlPatternSpec *spec);
DZL_AVAILABLE_IN_3_32
GtkSizeGroup *dzl_preferences_group_get_size_group (DzlPreferencesGroup *self,
guint column);
G_END_DECLS
......
......@@ -1002,6 +1002,81 @@ dzl_preferences_view_get_widget (DzlPreferences *preferences,
return tracked ? tracked->widget : NULL;
}
static guint
dzl_preferences_view_add_table_row_va (DzlPreferences *preferences,
const gchar *page_name,
const gchar *group_name,
GtkWidget *first_widget,
va_list args)
{
DzlPreferencesView *self = (DzlPreferencesView *)preferences;
DzlPreferencesViewPrivate *priv = dzl_preferences_view_get_instance_private (self);
DzlPreferencesGroup *group;
GtkWidget *page;
GtkWidget *column = first_widget;
GtkWidget *row;
GtkBox *box;
guint column_id = 0;
guint widget_id;
g_assert (DZL_IS_PREFERENCES_VIEW (self));
g_assert (page_name != NULL);
g_assert (group_name != NULL);
g_assert (GTK_IS_WIDGET (column));
page = dzl_preferences_view_get_page (self, page_name);
if (page == NULL)
{
g_warning ("No page named \"%s\" could be found.", page_name);
return 0;
}
group = dzl_preferences_page_get_group (DZL_PREFERENCES_PAGE (page), group_name);
if (group == NULL)
{
g_warning ("No such preferences group \"%s\" in page \"%s\"",
group_name, page_name);
return 0;
}
row = g_object_new (DZL_TYPE_PREFERENCES_BIN,
"visible", TRUE,
NULL);
box = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (box));
do
{
GtkSizeGroup *size_group;
if ((size_group = dzl_preferences_group_get_size_group (group, column_id)))
gtk_size_group_add_widget (size_group, column);
gtk_container_add_with_properties (GTK_CONTAINER (box), column,
"expand", FALSE,
NULL);
column = va_arg (args, GtkWidget*);
column_id++;
}
while (column != NULL);
dzl_preferences_group_add (group, GTK_WIDGET (row));
widget_id = ++priv->last_widget_id;
dzl_preferences_view_track (self, widget_id, GTK_WIDGET (row));
if ((row = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW)))
gtk_widget_set_can_focus (row, FALSE);
return widget_id;
}
static void
dzl_preferences_iface_init (DzlPreferencesInterface *iface)
{
......@@ -1017,6 +1092,7 @@ dzl_preferences_iface_init (DzlPreferencesInterface *iface)
iface->set_page = dzl_preferences_view_set_page;
iface->remove_id = dzl_preferences_view_remove_id;
iface->get_widget = dzl_preferences_view_get_widget;
iface->add_table_row_va = dzl_preferences_view_add_table_row_va;
}
GtkWidget *
......
......@@ -262,3 +262,25 @@ dzl_preferences_get_widget (DzlPreferences *self,
return DZL_PREFERENCES_GET_IFACE (self)->get_widget (self, widget_id);
}
guint
dzl_preferences_add_table_row (DzlPreferences *self,
const gchar *page_name,
const gchar *group_name,
GtkWidget *first_widget,
...)
{
va_list args;
gint ret;
g_return_val_if_fail (DZL_IS_PREFERENCES (self), 0);
g_return_val_if_fail (page_name != NULL, 0);
g_return_val_if_fail (group_name != NULL, 0);
g_return_val_if_fail (GTK_IS_WIDGET (first_widget), 0);
va_start (args, first_widget);
ret = DZL_PREFERENCES_GET_IFACE (self)->add_table_row_va (self, page_name, group_name, first_widget, args);
va_end (args);
return ret;
}
......@@ -113,6 +113,11 @@ struct _DzlPreferencesInterface
guint widget_id);
GtkWidget *(*get_widget) (DzlPreferences *self,
guint widget_id);
guint (*add_table_row_va) (DzlPreferences *self,
const gchar *page_name,
const gchar *group_name,
GtkWidget *first_widget,
va_list args);
};
DZL_AVAILABLE_IN_ALL
......@@ -206,6 +211,12 @@ void dzl_preferences_set_page (DzlPreferences *self,
DZL_AVAILABLE_IN_ALL
GtkWidget *dzl_preferences_get_widget (DzlPreferences *self,
guint widget_id);
DZL_AVAILABLE_IN_3_32
guint dzl_preferences_add_table_row (DzlPreferences *self,
const gchar *page_name,
const gchar *group_name,
GtkWidget *first_widget,
...) G_GNUC_NULL_TERMINATED;
G_END_DECLS
......
......@@ -26,7 +26,7 @@
#include "util/dzl-macros.h"
/**
* SECTION:trie
* SECTION:dzl-trie
* @title: DzlTrie
* @short_description: A generic prefix tree.
*
......
......@@ -82,6 +82,12 @@ typedef struct
*/
GNode *root;
/*
* GHashTable to match command/action to a nodedata, useful to generate
* a tooltip-text string for a given widget.
*/
GHashTable *command_id_to_node_data;
/*
* We keep track of the search paths for loading themes here. Each element is
* a string containing the path to the file-system resource. If the path
......@@ -302,6 +308,8 @@ dzl_shortcut_manager_finalize (GObject *object)
DzlShortcutManager *self = (DzlShortcutManager *)object;
DzlShortcutManagerPrivate *priv = dzl_shortcut_manager_get_instance_private (self);
g_clear_pointer (&priv->command_id_to_node_data, g_hash_table_unref);
if (priv->root != NULL)
{
g_node_traverse (priv->root, G_IN_ORDER, G_TRAVERSE_ALL, -1, free_node_data, NULL);
......@@ -449,6 +457,7 @@ dzl_shortcut_manager_init (DzlShortcutManager *self)
{
DzlShortcutManagerPrivate *priv = dzl_shortcut_manager_get_instance_private (self);
priv->command_id_to_node_data = g_hash_table_new (g_str_hash, g_str_equal);
priv->seen_entries = g_hash_table_new (shortcut_entry_hash, NULL);
priv->themes = g_ptr_array_new_with_free_func (destroy_theme);
priv->root = g_node_new (NULL);
......@@ -1310,6 +1319,7 @@ dzl_shortcut_manager_add_action (DzlShortcutManager *self,
const gchar *title,
const gchar *subtitle)
{
DzlShortcutManagerPrivate *priv;
DzlShortcutNodeData *data;
GNode *parent;
......@@ -1320,6 +1330,8 @@ dzl_shortcut_manager_add_action (DzlShortcutManager *self,
if (self == NULL)
self = dzl_shortcut_manager_get_default ();
priv = dzl_shortcut_manager_get_instance_private (self);
section = g_intern_string (section);
group = g_intern_string (group);
title = g_intern_string (title);
......@@ -1338,6 +1350,8 @@ dzl_shortcut_manager_add_action (DzlShortcutManager *self,
g_node_append_data (parent, data);
g_hash_table_insert (priv->command_id_to_node_data, (gpointer)data->name, data);
g_signal_emit (self, signals [CHANGED], 0);
}
......@@ -1349,6 +1363,7 @@ dzl_shortcut_manager_add_command (DzlShortcutManager *self,
const gchar *title,
const gchar *subtitle)
{
DzlShortcutManagerPrivate *priv;
DzlShortcutNodeData *data;
GNode *parent;
......@@ -1359,6 +1374,8 @@ dzl_shortcut_manager_add_command (DzlShortcutManager *self,
if (self == NULL)
self = dzl_shortcut_manager_get_default ();
priv = dzl_shortcut_manager_get_instance_private (self);
section = g_intern_string (section);
group = g_intern_string (group);
title = g_intern_string (title);
......@@ -1377,6 +1394,8 @@ dzl_shortcut_manager_add_command (DzlShortcutManager *self,
g_node_append_data (parent, data);
g_hash_table_insert (priv->command_id_to_node_data, (gpointer)data->name, data);
g_signal_emit (self, signals [CHANGED], 0);
}
......@@ -1667,3 +1686,46 @@ dzl_shortcut_manager_merge (DzlShortcutManager *self,
DZL_EXIT;
}
/**
* _dzl_shortcut_manager_get_command_info:
* @self: a #DzlShortcutManager
* @command_id: the command-id
* @title: (out) (optional): a location for the title
* @subtitle: (out) (optional): a location for the subtitle
*
* Gets command information about command-id
*
* Returns: %TRUE if the command-id was found and out parameters were set.
*
* Since: 3.32
*/
gboolean
_dzl_shortcut_manager_get_command_info (DzlShortcutManager *self,
const gchar *command_id,
const gchar **title,
const gchar **subtitle)
{
DzlShortcutManagerPrivate *priv;
DzlShortcutNodeData *node;
if (self == NULL)
self = dzl_shortcut_manager_get_default ();
g_return_val_if_fail (DZL_IS_SHORTCUT_MANAGER (self), FALSE);
priv = dzl_shortcut_manager_get_instance_private (self);
if ((node = g_hash_table_lookup (priv->command_id_to_node_data, command_id)))
{
if (title != NULL)
*title = node->title;
if (subtitle != NULL)
*subtitle = node->subtitle;
return TRUE;
}
return FALSE;
}
......@@ -150,6 +150,10 @@ gboolean _dzl_shortcut_chord_table_iter_next (DzlShortcut
const DzlShortcutChord **chord,
gpointer *value);
void _dzl_shortcut_chord_table_iter_steal (DzlShortcutChordTableIter *iter);
gboolean _dzl_shortcut_manager_get_command_info (DzlShortcutManager *self,
const gchar *command_id,
const gchar **title,
const gchar **subtitle);
static inline gboolean
DZL_IS_SHORTCUT_CLOSURE_CHAIN (DzlShortcutClosureChain *self)
......
This diff is collapsed.
/* dzl-shortcut-tooltip.h
*
* Copyright 2018 Christian Hergert <chergert@redhat.com>
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
#include "dzl-version-macros.h"
G_BEGIN_DECLS
#define DZL_TYPE_SHORTCUT_TOOLTIP (dzl_shortcut_tooltip_get_type())
DZL_AVAILABLE_IN_3_32
G_DECLARE_FINAL_TYPE (DzlShortcutTooltip, dzl_shortcut_tooltip, DZL, SHORTCUT_TOOLTIP, GObject)
DZL_AVAILABLE_IN_3_32
DzlShortcutTooltip *dzl_shortcut_tooltip_new (void);
DZL_AVAILABLE_IN_3_32
const gchar *dzl_shortcut_tooltip_get_accel (DzlShortcutTooltip *self);
DZL_AVAILABLE_IN_3_32
void dzl_shortcut_tooltip_set_accel (DzlShortcutTooltip *self,
const gchar *accel);
DZL_AVAILABLE_IN_3_32
GtkWidget *dzl_shortcut_tooltip_get_widget (DzlShortcutTooltip *self);
DZL_AVAILABLE_IN_3_32
void dzl_shortcut_tooltip_set_widget (DzlShortcutTooltip *self,
GtkWidget *widget);
DZL_AVAILABLE_IN_3_32
const gchar *dzl_shortcut_tooltip_get_command_id (DzlShortcutTooltip *self);
DZL_AVAILABLE_IN_3_32
void dzl_shortcut_tooltip_set_command_id (DzlShortcutTooltip *self,
const gchar *command_id);
DZL_AVAILABLE_IN_3_32
const gchar *dzl_shortcut_tooltip_get_title (DzlShortcutTooltip *self);