mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-02-12 16:10:54 +00:00
Merge branch 'wip/chergert/libsysprof-analyze'
This merges a mostly completed rewrite of Sysprof using all the new GTK features we can muster. In particular, we now have SysprofDocument which can be used to read documents instead of SysprofCaptureReader for a more document-oriented experience. It's mmap-based and has significantly more indexing capabilities for new features. The recording process still needs a bit more work, along with opening documents and custom debug-dirs. Some applications are expected to break, such as gnome-builder which will have to stop using the now-extinct libsysprof-ui library. Instead applications should open the capture files with Sysprof directly.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.flatpak-builder
|
||||
*.swp
|
||||
*~
|
||||
build
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
#mesondefine HAVE_EXECINFO_H
|
||||
|
||||
#mesondefine HAVE_LIBSYSTEMD
|
||||
|
||||
#mesondefine HAVE_PERF_CLOCKID
|
||||
|
||||
#mesondefine HAVE_POLKIT
|
||||
|
||||
202
contrib/eggbitset/COPYING
Normal file
202
contrib/eggbitset/COPYING
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
16
contrib/eggbitset/README.md
Normal file
16
contrib/eggbitset/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
Roaring bitmaps implementation
|
||||
==============================
|
||||
|
||||
This directory contains code modified for GTK, based on the Roaring
|
||||
bitmaps reference implementation
|
||||
[CRoaring](https://github.com/RoaringBitmap/CRoaring).
|
||||
|
||||
It is not necessarily compatible with past or future versions of CRoaring,
|
||||
and replacing it with a different version or linking to a system copy
|
||||
is not supported.
|
||||
|
||||
See the source files for copyright and licensing information, and the
|
||||
`COPYING` file for the full text of the Apache license, version 2.0.
|
||||
|
||||
When proposing modifications for these files, please consider whether they
|
||||
are also suitable for submission to CRoaring.
|
||||
984
contrib/eggbitset/eggbitset.c
Normal file
984
contrib/eggbitset/eggbitset.c
Normal file
@ -0,0 +1,984 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "eggbitset.h"
|
||||
|
||||
#include "roaring.c"
|
||||
|
||||
/**
|
||||
* EggBitset: (ref-func egg_bitset_ref) (unref-func egg_bitset_unref)
|
||||
*
|
||||
* A `EggBitset` represents a set of unsigned integers.
|
||||
*
|
||||
* Another name for this data structure is "bitmap".
|
||||
*
|
||||
* The current implementation is based on [roaring bitmaps](https://roaringbitmap.org/).
|
||||
*
|
||||
* A bitset allows adding a set of integers and provides support for set operations
|
||||
* like unions, intersections and checks for equality or if a value is contained
|
||||
* in the set. `EggBitset` also contains various functions to query metadata about
|
||||
* the bitset, such as the minimum or maximum values or its size.
|
||||
*
|
||||
* The fastest way to iterate values in a bitset is [struct@Egg.BitsetIter].
|
||||
*
|
||||
* The main use case for `EggBitset` is implementing complex selections for
|
||||
* [iface@Egg.SelectionModel].
|
||||
*/
|
||||
|
||||
struct _EggBitset
|
||||
{
|
||||
int ref_count;
|
||||
roaring_bitmap_t roaring;
|
||||
};
|
||||
|
||||
|
||||
G_DEFINE_BOXED_TYPE (EggBitset, egg_bitset,
|
||||
egg_bitset_ref,
|
||||
egg_bitset_unref)
|
||||
|
||||
/**
|
||||
* egg_bitset_ref:
|
||||
* @self: (nullable): a `EggBitset`
|
||||
*
|
||||
* Acquires a reference on the given `EggBitset`.
|
||||
*
|
||||
* Returns: (transfer none): the `EggBitset` with an additional reference
|
||||
*/
|
||||
EggBitset *
|
||||
egg_bitset_ref (EggBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
|
||||
self->ref_count += 1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_unref:
|
||||
* @self: (nullable): a `EggBitset`
|
||||
*
|
||||
* Releases a reference on the given `EggBitset`.
|
||||
*
|
||||
* If the reference was the last, the resources associated to the @self are
|
||||
* freed.
|
||||
*/
|
||||
void
|
||||
egg_bitset_unref (EggBitset *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->ref_count > 0);
|
||||
|
||||
self->ref_count -= 1;
|
||||
if (self->ref_count > 0)
|
||||
return;
|
||||
|
||||
ra_clear (&self->roaring.high_low_container);
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_contains:
|
||||
* @self: a `EggBitset`
|
||||
* @value: the value to check
|
||||
*
|
||||
* Checks if the given @value has been added to @self
|
||||
*
|
||||
* Returns: %TRUE if @self contains @value
|
||||
**/
|
||||
gboolean
|
||||
egg_bitset_contains (const EggBitset *self,
|
||||
guint value)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
|
||||
return roaring_bitmap_contains (&self->roaring, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_is_empty:
|
||||
* @self: a `EggBitset`
|
||||
*
|
||||
* Check if no value is contained in bitset.
|
||||
*
|
||||
* Returns: %TRUE if @self is empty
|
||||
**/
|
||||
gboolean
|
||||
egg_bitset_is_empty (const EggBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, TRUE);
|
||||
|
||||
return roaring_bitmap_is_empty (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_equals:
|
||||
* @self: a `EggBitset`
|
||||
* @other: another `EggBitset`
|
||||
*
|
||||
* Returns %TRUE if @self and @other contain the same values.
|
||||
*
|
||||
* Returns: %TRUE if @self and @other contain the same values
|
||||
**/
|
||||
gboolean
|
||||
egg_bitset_equals (const EggBitset *self,
|
||||
const EggBitset *other)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, other == NULL);
|
||||
g_return_val_if_fail (other != NULL, FALSE);
|
||||
|
||||
if (self == other)
|
||||
return TRUE;
|
||||
|
||||
return roaring_bitmap_equals (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_get_minimum:
|
||||
* @self: a `EggBitset`
|
||||
*
|
||||
* Returns the smallest value in @self.
|
||||
*
|
||||
* If @self is empty, `G_MAXUINT` is returned.
|
||||
*
|
||||
* Returns: The smallest value in @self
|
||||
**/
|
||||
guint
|
||||
egg_bitset_get_minimum (const EggBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, G_MAXUINT);
|
||||
|
||||
return roaring_bitmap_minimum (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_get_maximum:
|
||||
* @self: a `EggBitset`
|
||||
*
|
||||
* Returns the largest value in @self.
|
||||
*
|
||||
* If @self is empty, 0 is returned.
|
||||
*
|
||||
* Returns: The largest value in @self
|
||||
**/
|
||||
guint
|
||||
egg_bitset_get_maximum (const EggBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
|
||||
return roaring_bitmap_maximum (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_get_size:
|
||||
* @self: a `EggBitset`
|
||||
*
|
||||
* Gets the number of values that were added to the set.
|
||||
*
|
||||
* For example, if the set is empty, 0 is returned.
|
||||
*
|
||||
* Note that this function returns a `guint64`, because when all
|
||||
* values are set, the return value is `G_MAXUINT + 1`. Unless you
|
||||
* are sure this cannot happen (it can't with `GListModel`), be sure
|
||||
* to use a 64bit type.
|
||||
*
|
||||
* Returns: The number of values in the set.
|
||||
*/
|
||||
guint64
|
||||
egg_bitset_get_size (const EggBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
|
||||
return roaring_bitmap_get_cardinality (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_get_size_in_range:
|
||||
* @self: a `EggBitset`
|
||||
* @first: the first element to include
|
||||
* @last: the last element to include
|
||||
*
|
||||
* Gets the number of values that are part of the set from @first to @last
|
||||
* (inclusive).
|
||||
*
|
||||
* Note that this function returns a `guint64`, because when all values are
|
||||
* set, the return value is `G_MAXUINT + 1`. Unless you are sure this cannot
|
||||
* happen (it can't with `GListModel`), be sure to use a 64bit type.
|
||||
*
|
||||
* Returns: The number of values in the set from @first to @last.
|
||||
*/
|
||||
guint64
|
||||
egg_bitset_get_size_in_range (const EggBitset *self,
|
||||
guint first,
|
||||
guint last)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
g_return_val_if_fail (last >= first, 0);
|
||||
|
||||
return roaring_bitmap_range_cardinality (&self->roaring, first, ((uint64_t) last) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_get_nth:
|
||||
* @self: a `EggBitset`
|
||||
* @nth: index of the item to get
|
||||
*
|
||||
* Returns the value of the @nth item in self.
|
||||
*
|
||||
* If @nth is >= the size of @self, 0 is returned.
|
||||
*
|
||||
* Returns: the value of the @nth item in @self
|
||||
*/
|
||||
guint
|
||||
egg_bitset_get_nth (const EggBitset *self,
|
||||
guint nth)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
if (!roaring_bitmap_select (&self->roaring, nth, &result))
|
||||
return 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_new_empty:
|
||||
*
|
||||
* Creates a new empty bitset.
|
||||
*
|
||||
* Returns: A new empty bitset
|
||||
*/
|
||||
EggBitset *
|
||||
egg_bitset_new_empty (void)
|
||||
{
|
||||
EggBitset *self;
|
||||
|
||||
self = g_new0 (EggBitset, 1);
|
||||
|
||||
self->ref_count = 1;
|
||||
|
||||
ra_init (&self->roaring.high_low_container);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_new_range:
|
||||
* @start: first value to add
|
||||
* @n_items: number of consecutive values to add
|
||||
*
|
||||
* Creates a bitset with the given range set.
|
||||
*
|
||||
* Returns: A new bitset
|
||||
**/
|
||||
EggBitset *
|
||||
egg_bitset_new_range (guint start,
|
||||
guint n_items)
|
||||
{
|
||||
EggBitset *self;
|
||||
|
||||
self = egg_bitset_new_empty ();
|
||||
|
||||
egg_bitset_add_range (self, start, n_items);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_copy:
|
||||
* @self: a `EggBitset`
|
||||
*
|
||||
* Creates a copy of @self.
|
||||
*
|
||||
* Returns: (transfer full): A new bitset that contains the same
|
||||
* values as @self
|
||||
*/
|
||||
EggBitset *
|
||||
egg_bitset_copy (const EggBitset *self)
|
||||
{
|
||||
EggBitset *copy;
|
||||
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
|
||||
copy = egg_bitset_new_empty ();
|
||||
roaring_bitmap_overwrite (©->roaring, &self->roaring);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_remove_all:
|
||||
* @self: a `EggBitset`
|
||||
*
|
||||
* Removes all values from the bitset so that it is empty again.
|
||||
*/
|
||||
void
|
||||
egg_bitset_remove_all (EggBitset *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
roaring_bitmap_clear (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_add:
|
||||
* @self: a `EggBitset`
|
||||
* @value: value to add
|
||||
*
|
||||
* Adds @value to @self if it wasn't part of it before.
|
||||
*
|
||||
* Returns: %TRUE if @value was not part of @self and @self
|
||||
* was changed
|
||||
*/
|
||||
gboolean
|
||||
egg_bitset_add (EggBitset *self,
|
||||
guint value)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
|
||||
return roaring_bitmap_add_checked (&self->roaring, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_remove:
|
||||
* @self: a `EggBitset`
|
||||
* @value: value to remove
|
||||
*
|
||||
* Removes @value from @self if it was part of it before.
|
||||
*
|
||||
* Returns: %TRUE if @value was part of @self and @self
|
||||
* was changed
|
||||
*/
|
||||
gboolean
|
||||
egg_bitset_remove (EggBitset *self,
|
||||
guint value)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
|
||||
return roaring_bitmap_remove_checked (&self->roaring, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_add_range:
|
||||
* @self: a `EggBitset`
|
||||
* @start: first value to add
|
||||
* @n_items: number of consecutive values to add
|
||||
*
|
||||
* Adds all values from @start (inclusive) to @start + @n_items
|
||||
* (exclusive) in @self.
|
||||
*/
|
||||
void
|
||||
egg_bitset_add_range (EggBitset *self,
|
||||
guint start,
|
||||
guint n_items)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
if (n_items == 0)
|
||||
return;
|
||||
|
||||
/* overflow check, the == 0 is to allow add_range(G_MAXUINT, 1); */
|
||||
g_return_if_fail (start + n_items == 0 || start + n_items > start);
|
||||
|
||||
roaring_bitmap_add_range_closed (&self->roaring, start, start + n_items - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_remove_range:
|
||||
* @self: a `EggBitset`
|
||||
* @start: first value to remove
|
||||
* @n_items: number of consecutive values to remove
|
||||
*
|
||||
* Removes all values from @start (inclusive) to @start + @n_items (exclusive)
|
||||
* in @self.
|
||||
*/
|
||||
void
|
||||
egg_bitset_remove_range (EggBitset *self,
|
||||
guint start,
|
||||
guint n_items)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
if (n_items == 0)
|
||||
return;
|
||||
|
||||
/* overflow check, the == 0 is to allow add_range(G_MAXUINT, 1); */
|
||||
g_return_if_fail (start + n_items == 0 || start + n_items > start);
|
||||
|
||||
roaring_bitmap_remove_range_closed (&self->roaring, start, start + n_items - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_add_range_closed:
|
||||
* @self: a `EggBitset`
|
||||
* @first: first value to add
|
||||
* @last: last value to add
|
||||
*
|
||||
* Adds the closed range [@first, @last], so @first, @last and all
|
||||
* values in between. @first must be smaller than @last.
|
||||
*/
|
||||
void
|
||||
egg_bitset_add_range_closed (EggBitset *self,
|
||||
guint first,
|
||||
guint last)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (first <= last);
|
||||
|
||||
roaring_bitmap_add_range_closed (&self->roaring, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_remove_range_closed:
|
||||
* @self: a `EggBitset`
|
||||
* @first: first value to remove
|
||||
* @last: last value to remove
|
||||
*
|
||||
* Removes the closed range [@first, @last], so @first, @last and all
|
||||
* values in between. @first must be smaller than @last.
|
||||
*/
|
||||
void
|
||||
egg_bitset_remove_range_closed (EggBitset *self,
|
||||
guint first,
|
||||
guint last)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (first <= last);
|
||||
|
||||
roaring_bitmap_remove_range_closed (&self->roaring, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_add_rectangle:
|
||||
* @self: a `EggBitset`
|
||||
* @start: first value to add
|
||||
* @width: width of the rectangle
|
||||
* @height: height of the rectangle
|
||||
* @stride: row stride of the grid
|
||||
*
|
||||
* Interprets the values as a 2-dimensional boolean grid with the given @stride
|
||||
* and inside that grid, adds a rectangle with the given @width and @height.
|
||||
*/
|
||||
void
|
||||
egg_bitset_add_rectangle (EggBitset *self,
|
||||
guint start,
|
||||
guint width,
|
||||
guint height,
|
||||
guint stride)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail ((start % stride) + width <= stride);
|
||||
g_return_if_fail (G_MAXUINT - start >= height * stride);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
egg_bitset_add_range (self, i * stride + start, width);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_remove_rectangle:
|
||||
* @self: a `EggBitset`
|
||||
* @start: first value to remove
|
||||
* @width: width of the rectangle
|
||||
* @height: height of the rectangle
|
||||
* @stride: row stride of the grid
|
||||
*
|
||||
* Interprets the values as a 2-dimensional boolean grid with the given @stride
|
||||
* and inside that grid, removes a rectangle with the given @width and @height.
|
||||
*/
|
||||
void
|
||||
egg_bitset_remove_rectangle (EggBitset *self,
|
||||
guint start,
|
||||
guint width,
|
||||
guint height,
|
||||
guint stride)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (width <= stride);
|
||||
g_return_if_fail (G_MAXUINT - start >= height * stride);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
egg_bitset_remove_range (self, i * stride + start, width);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_union:
|
||||
* @self: a `EggBitset`
|
||||
* @other: the `EggBitset` to union with
|
||||
*
|
||||
* Sets @self to be the union of @self and @other.
|
||||
*
|
||||
* That is, add all values from @other into @self that weren't part of it.
|
||||
*
|
||||
* It is allowed for @self and @other to be the same bitset. Nothing will
|
||||
* happen in that case.
|
||||
*/
|
||||
void
|
||||
egg_bitset_union (EggBitset *self,
|
||||
const EggBitset *other)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
if (self == other)
|
||||
return;
|
||||
|
||||
roaring_bitmap_or_inplace (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_intersect:
|
||||
* @self: a `EggBitset`
|
||||
* @other: the `EggBitset` to intersect with
|
||||
*
|
||||
* Sets @self to be the intersection of @self and @other.
|
||||
*
|
||||
* In other words, remove all values from @self that are not part of @other.
|
||||
*
|
||||
* It is allowed for @self and @other to be the same bitset. Nothing will
|
||||
* happen in that case.
|
||||
*/
|
||||
void
|
||||
egg_bitset_intersect (EggBitset *self,
|
||||
const EggBitset *other)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
if (self == other)
|
||||
return;
|
||||
|
||||
roaring_bitmap_and_inplace (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_subtract:
|
||||
* @self: a `EggBitset`
|
||||
* @other: the `EggBitset` to subtract
|
||||
*
|
||||
* Sets @self to be the subtraction of @other from @self.
|
||||
*
|
||||
* In other words, remove all values from @self that are part of @other.
|
||||
*
|
||||
* It is allowed for @self and @other to be the same bitset. The bitset
|
||||
* will be emptied in that case.
|
||||
*/
|
||||
void
|
||||
egg_bitset_subtract (EggBitset *self,
|
||||
const EggBitset *other)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
if (self == other)
|
||||
{
|
||||
roaring_bitmap_clear (&self->roaring);
|
||||
return;
|
||||
}
|
||||
|
||||
roaring_bitmap_andnot_inplace (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_difference:
|
||||
* @self: a `EggBitset`
|
||||
* @other: the `EggBitset` to compute the difference from
|
||||
*
|
||||
* Sets @self to be the symmetric difference of @self and @other.
|
||||
*
|
||||
* The symmetric difference is set @self to contain all values that
|
||||
* were either contained in @self or in @other, but not in both.
|
||||
* This operation is also called an XOR.
|
||||
*
|
||||
* It is allowed for @self and @other to be the same bitset. The bitset
|
||||
* will be emptied in that case.
|
||||
*/
|
||||
void
|
||||
egg_bitset_difference (EggBitset *self,
|
||||
const EggBitset *other)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
if (self == other)
|
||||
{
|
||||
roaring_bitmap_clear (&self->roaring);
|
||||
return;
|
||||
}
|
||||
|
||||
roaring_bitmap_xor_inplace (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_shift_left:
|
||||
* @self: a `EggBitset`
|
||||
* @amount: amount to shift all values to the left
|
||||
*
|
||||
* Shifts all values in @self to the left by @amount.
|
||||
*
|
||||
* Values smaller than @amount are discarded.
|
||||
*/
|
||||
void
|
||||
egg_bitset_shift_left (EggBitset *self,
|
||||
guint amount)
|
||||
{
|
||||
EggBitset *original;
|
||||
EggBitsetIter iter;
|
||||
guint value;
|
||||
gboolean loop;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
if (amount == 0)
|
||||
return;
|
||||
|
||||
original = egg_bitset_copy (self);
|
||||
egg_bitset_remove_all (self);
|
||||
|
||||
for (loop = egg_bitset_iter_init_at (&iter, original, amount, &value);
|
||||
loop;
|
||||
loop = egg_bitset_iter_next (&iter, &value))
|
||||
{
|
||||
egg_bitset_add (self, value - amount);
|
||||
}
|
||||
|
||||
egg_bitset_unref (original);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_shift_right:
|
||||
* @self: a `EggBitset`
|
||||
* @amount: amount to shift all values to the right
|
||||
*
|
||||
* Shifts all values in @self to the right by @amount.
|
||||
*
|
||||
* Values that end up too large to be held in a #guint are discarded.
|
||||
*/
|
||||
void
|
||||
egg_bitset_shift_right (EggBitset *self,
|
||||
guint amount)
|
||||
{
|
||||
EggBitset *original;
|
||||
EggBitsetIter iter;
|
||||
guint value;
|
||||
gboolean loop;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
if (amount == 0)
|
||||
return;
|
||||
|
||||
original = egg_bitset_copy (self);
|
||||
egg_bitset_remove_all (self);
|
||||
|
||||
for (loop = egg_bitset_iter_init_first (&iter, original, &value);
|
||||
loop && value <= G_MAXUINT - amount;
|
||||
loop = egg_bitset_iter_next (&iter, &value))
|
||||
{
|
||||
egg_bitset_add (self, value + amount);
|
||||
}
|
||||
|
||||
egg_bitset_unref (original);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_splice:
|
||||
* @self: a `EggBitset`
|
||||
* @position: position at which to slice
|
||||
* @removed: number of values to remove
|
||||
* @added: number of values to add
|
||||
*
|
||||
* This is a support function for `GListModel` handling, by mirroring
|
||||
* the `GlistModel::items-changed` signal.
|
||||
*
|
||||
* First, it "cuts" the values from @position to @removed from
|
||||
* the bitset. That is, it removes all those values and shifts
|
||||
* all larger values to the left by @removed places.
|
||||
*
|
||||
* Then, it "pastes" new room into the bitset by shifting all values
|
||||
* larger than @position by @added spaces to the right. This frees
|
||||
* up space that can then be filled.
|
||||
*/
|
||||
void
|
||||
egg_bitset_splice (EggBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
/* overflow */
|
||||
g_return_if_fail (position + removed >= position);
|
||||
g_return_if_fail (position + added >= position);
|
||||
|
||||
egg_bitset_remove_range (self, position, removed);
|
||||
|
||||
if (removed != added)
|
||||
{
|
||||
EggBitset *shift = egg_bitset_copy (self);
|
||||
|
||||
egg_bitset_remove_range (shift, 0, position);
|
||||
egg_bitset_remove_range_closed (self, position, G_MAXUINT);
|
||||
if (added > removed)
|
||||
egg_bitset_shift_right (shift, added - removed);
|
||||
else
|
||||
egg_bitset_shift_left (shift, removed - added);
|
||||
egg_bitset_union (self, shift);
|
||||
egg_bitset_unref (shift);
|
||||
}
|
||||
}
|
||||
|
||||
G_STATIC_ASSERT (sizeof (EggBitsetIter) >= sizeof (roaring_uint32_iterator_t));
|
||||
|
||||
static EggBitsetIter *
|
||||
egg_bitset_iter_copy (EggBitsetIter *iter)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
return (EggBitsetIter *) roaring_copy_uint32_iterator (riter);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_bitset_iter_free (EggBitsetIter *iter)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
roaring_free_uint32_iterator (riter);
|
||||
}
|
||||
|
||||
G_DEFINE_BOXED_TYPE (EggBitsetIter, egg_bitset_iter, egg_bitset_iter_copy, egg_bitset_iter_free)
|
||||
|
||||
/**
|
||||
* egg_bitset_iter_init_first:
|
||||
* @iter: (out): a pointer to an uninitialized `EggBitsetIter`
|
||||
* @set: a `EggBitset`
|
||||
* @value: (out) (optional): Set to the first value in @set
|
||||
*
|
||||
* Initializes an iterator for @set and points it to the first
|
||||
* value in @set.
|
||||
*
|
||||
* If @set is empty, %FALSE is returned and @value is set to %G_MAXUINT.
|
||||
*
|
||||
* Returns: %TRUE if @set isn't empty.
|
||||
*/
|
||||
gboolean
|
||||
egg_bitset_iter_init_first (EggBitsetIter *iter,
|
||||
const EggBitset *set,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
g_return_val_if_fail (set != NULL, FALSE);
|
||||
|
||||
roaring_init_iterator (&set->roaring, riter);
|
||||
|
||||
if (value)
|
||||
*value = riter->has_value ? riter->current_value : 0;
|
||||
|
||||
return riter->has_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_iter_init_last:
|
||||
* @iter: (out): a pointer to an uninitialized `EggBitsetIter`
|
||||
* @set: a `EggBitset`
|
||||
* @value: (out) (optional): Set to the last value in @set
|
||||
*
|
||||
* Initializes an iterator for @set and points it to the last
|
||||
* value in @set.
|
||||
*
|
||||
* If @set is empty, %FALSE is returned.
|
||||
*
|
||||
* Returns: %TRUE if @set isn't empty.
|
||||
**/
|
||||
gboolean
|
||||
egg_bitset_iter_init_last (EggBitsetIter *iter,
|
||||
const EggBitset *set,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
g_return_val_if_fail (set != NULL, FALSE);
|
||||
|
||||
roaring_init_iterator_last (&set->roaring, riter);
|
||||
|
||||
if (value)
|
||||
*value = riter->has_value ? riter->current_value : 0;
|
||||
|
||||
return riter->has_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_iter_init_at:
|
||||
* @iter: (out): a pointer to an uninitialized `EggBitsetIter`
|
||||
* @set: a `EggBitset`
|
||||
* @target: target value to start iterating at
|
||||
* @value: (out) (optional): Set to the found value in @set
|
||||
*
|
||||
* Initializes @iter to point to @target.
|
||||
*
|
||||
* If @target is not found, finds the next value after it.
|
||||
* If no value >= @target exists in @set, this function returns %FALSE.
|
||||
*
|
||||
* Returns: %TRUE if a value was found.
|
||||
*/
|
||||
gboolean
|
||||
egg_bitset_iter_init_at (EggBitsetIter *iter,
|
||||
const EggBitset *set,
|
||||
guint target,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
g_return_val_if_fail (set != NULL, FALSE);
|
||||
|
||||
roaring_init_iterator (&set->roaring, riter);
|
||||
if (!roaring_move_uint32_iterator_equalorlarger (riter, target))
|
||||
{
|
||||
if (value)
|
||||
*value = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = riter->current_value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_iter_next:
|
||||
* @iter: a pointer to a valid `EggBitsetIter`
|
||||
* @value: (out) (optional): Set to the next value
|
||||
*
|
||||
* Moves @iter to the next value in the set.
|
||||
*
|
||||
* If it was already pointing to the last value in the set,
|
||||
* %FALSE is returned and @iter is invalidated.
|
||||
*
|
||||
* Returns: %TRUE if a next value existed
|
||||
*/
|
||||
gboolean
|
||||
egg_bitset_iter_next (EggBitsetIter *iter,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
|
||||
if (!roaring_advance_uint32_iterator (riter))
|
||||
{
|
||||
if (value)
|
||||
*value = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = riter->current_value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_iter_previous:
|
||||
* @iter: a pointer to a valid `EggBitsetIter`
|
||||
* @value: (out) (optional): Set to the previous value
|
||||
*
|
||||
* Moves @iter to the previous value in the set.
|
||||
*
|
||||
* If it was already pointing to the first value in the set,
|
||||
* %FALSE is returned and @iter is invalidated.
|
||||
*
|
||||
* Returns: %TRUE if a previous value existed
|
||||
*/
|
||||
gboolean
|
||||
egg_bitset_iter_previous (EggBitsetIter *iter,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
|
||||
if (!roaring_previous_uint32_iterator (riter))
|
||||
{
|
||||
if (value)
|
||||
*value = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = riter->current_value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_iter_get_value:
|
||||
* @iter: a `EggBitsetIter`
|
||||
*
|
||||
* Gets the current value that @iter points to.
|
||||
*
|
||||
* If @iter is not valid and [method@Egg.BitsetIter.is_valid]
|
||||
* returns %FALSE, this function returns 0.
|
||||
*
|
||||
* Returns: The current value pointer to by @iter
|
||||
*/
|
||||
guint
|
||||
egg_bitset_iter_get_value (const EggBitsetIter *iter)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, 0);
|
||||
|
||||
if (!riter->has_value)
|
||||
return 0;
|
||||
|
||||
return riter->current_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_bitset_iter_is_valid:
|
||||
* @iter: a `EggBitsetIter`
|
||||
*
|
||||
* Checks if @iter points to a valid value.
|
||||
*
|
||||
* Returns: %TRUE if @iter points to a valid value
|
||||
*/
|
||||
gboolean
|
||||
egg_bitset_iter_is_valid (const EggBitsetIter *iter)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
|
||||
return riter->has_value;
|
||||
}
|
||||
137
contrib/eggbitset/eggbitset.h
Normal file
137
contrib/eggbitset/eggbitset.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EGG_TYPE_BITSET (egg_bitset_get_type ())
|
||||
|
||||
typedef struct _EggBitset EggBitset;
|
||||
|
||||
GType egg_bitset_get_type (void) G_GNUC_CONST;
|
||||
EggBitset * egg_bitset_ref (EggBitset *self);
|
||||
void egg_bitset_unref (EggBitset *self);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(EggBitset, egg_bitset_unref)
|
||||
|
||||
gboolean egg_bitset_contains (const EggBitset *self,
|
||||
guint value);
|
||||
gboolean egg_bitset_is_empty (const EggBitset *self);
|
||||
gboolean egg_bitset_equals (const EggBitset *self,
|
||||
const EggBitset *other);
|
||||
guint64 egg_bitset_get_size (const EggBitset *self);
|
||||
guint64 egg_bitset_get_size_in_range (const EggBitset *self,
|
||||
guint first,
|
||||
guint last);
|
||||
guint egg_bitset_get_nth (const EggBitset *self,
|
||||
guint nth);
|
||||
guint egg_bitset_get_minimum (const EggBitset *self);
|
||||
guint egg_bitset_get_maximum (const EggBitset *self);
|
||||
|
||||
EggBitset * egg_bitset_new_empty (void);
|
||||
EggBitset * egg_bitset_copy (const EggBitset *self);
|
||||
EggBitset * egg_bitset_new_range (guint start,
|
||||
guint n_items);
|
||||
|
||||
void egg_bitset_remove_all (EggBitset *self);
|
||||
gboolean egg_bitset_add (EggBitset *self,
|
||||
guint value);
|
||||
gboolean egg_bitset_remove (EggBitset *self,
|
||||
guint value);
|
||||
void egg_bitset_add_range (EggBitset *self,
|
||||
guint start,
|
||||
guint n_items);
|
||||
void egg_bitset_remove_range (EggBitset *self,
|
||||
guint start,
|
||||
guint n_items);
|
||||
void egg_bitset_add_range_closed (EggBitset *self,
|
||||
guint first,
|
||||
guint last);
|
||||
void egg_bitset_remove_range_closed (EggBitset *self,
|
||||
guint first,
|
||||
guint last);
|
||||
void egg_bitset_add_rectangle (EggBitset *self,
|
||||
guint start,
|
||||
guint width,
|
||||
guint height,
|
||||
guint stride);
|
||||
void egg_bitset_remove_rectangle (EggBitset *self,
|
||||
guint start,
|
||||
guint width,
|
||||
guint height,
|
||||
guint stride);
|
||||
|
||||
void egg_bitset_union (EggBitset *self,
|
||||
const EggBitset *other);
|
||||
void egg_bitset_intersect (EggBitset *self,
|
||||
const EggBitset *other);
|
||||
void egg_bitset_subtract (EggBitset *self,
|
||||
const EggBitset *other);
|
||||
void egg_bitset_difference (EggBitset *self,
|
||||
const EggBitset *other);
|
||||
void egg_bitset_shift_left (EggBitset *self,
|
||||
guint amount);
|
||||
void egg_bitset_shift_right (EggBitset *self,
|
||||
guint amount);
|
||||
void egg_bitset_splice (EggBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added);
|
||||
|
||||
/**
|
||||
* EggBitsetIter:
|
||||
*
|
||||
* An opaque, stack-allocated struct for iterating
|
||||
* over the elements of a `EggBitset`.
|
||||
*
|
||||
* Before a `EggBitsetIter` can be used, it needs to be initialized with
|
||||
* [func@Egg.BitsetIter.init_first], [func@Egg.BitsetIter.init_last]
|
||||
* or [func@Egg.BitsetIter.init_at].
|
||||
*/
|
||||
typedef struct _EggBitsetIter EggBitsetIter;
|
||||
|
||||
struct _EggBitsetIter
|
||||
{
|
||||
/*< private >*/
|
||||
gpointer private_data[10];
|
||||
};
|
||||
|
||||
GType egg_bitset_iter_get_type (void) G_GNUC_CONST;
|
||||
gboolean egg_bitset_iter_init_first (EggBitsetIter *iter,
|
||||
const EggBitset *set,
|
||||
guint *value);
|
||||
gboolean egg_bitset_iter_init_last (EggBitsetIter *iter,
|
||||
const EggBitset *set,
|
||||
guint *value);
|
||||
gboolean egg_bitset_iter_init_at (EggBitsetIter *iter,
|
||||
const EggBitset *set,
|
||||
guint target,
|
||||
guint *value);
|
||||
gboolean egg_bitset_iter_next (EggBitsetIter *iter,
|
||||
guint *value);
|
||||
gboolean egg_bitset_iter_previous (EggBitsetIter *iter,
|
||||
guint *value);
|
||||
guint egg_bitset_iter_get_value (const EggBitsetIter *iter);
|
||||
gboolean egg_bitset_iter_is_valid (const EggBitsetIter *iter);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
17
contrib/eggbitset/meson.build
Normal file
17
contrib/eggbitset/meson.build
Normal file
@ -0,0 +1,17 @@
|
||||
libeggbitset_sources = [
|
||||
'eggbitset.c',
|
||||
]
|
||||
|
||||
libeggbitset_deps = [
|
||||
dependency('gio-2.0', version: glib_req_version),
|
||||
]
|
||||
|
||||
libeggbitset_static = static_library('eggbitset', libeggbitset_sources,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
dependencies: libeggbitset_deps,
|
||||
)
|
||||
|
||||
libeggbitset_static_dep = declare_dependency(
|
||||
include_directories: include_directories('.'),
|
||||
link_with: libeggbitset_static,
|
||||
)
|
||||
11475
contrib/eggbitset/roaring.c
Normal file
11475
contrib/eggbitset/roaring.c
Normal file
File diff suppressed because it is too large
Load Diff
7090
contrib/eggbitset/roaring.h
Normal file
7090
contrib/eggbitset/roaring.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -297,6 +297,37 @@ open_mapped_file (const char *filename,
|
||||
return file;
|
||||
}
|
||||
|
||||
ElfParser *
|
||||
elf_parser_new_from_mmap (GMappedFile *file,
|
||||
GError **error)
|
||||
{
|
||||
const guchar *data;
|
||||
gsize length;
|
||||
ElfParser *parser;
|
||||
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
|
||||
data = (guchar *)g_mapped_file_get_contents (file);
|
||||
length = g_mapped_file_get_length (file);
|
||||
parser = elf_parser_new_from_data (data, length);
|
||||
|
||||
if (!parser)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
G_FILE_ERROR_FAILED,
|
||||
"Failed to load ELF from mmap region");
|
||||
g_mapped_file_unref (file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parser->filename = NULL;
|
||||
parser->file = file;
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
ElfParser *
|
||||
elf_parser_new (const char *filename,
|
||||
GError **error)
|
||||
@ -27,6 +27,8 @@ typedef struct ElfParser ElfParser;
|
||||
|
||||
ElfParser *elf_parser_new_from_data (const guchar *data,
|
||||
gsize length);
|
||||
ElfParser *elf_parser_new_from_mmap (GMappedFile *mapped_file,
|
||||
GError **err);
|
||||
ElfParser *elf_parser_new (const char *filename,
|
||||
GError **err);
|
||||
void elf_parser_free (ElfParser *parser);
|
||||
19
contrib/elfparser/meson.build
Normal file
19
contrib/elfparser/meson.build
Normal file
@ -0,0 +1,19 @@
|
||||
libelfparser_sources = [
|
||||
'demangle.cpp',
|
||||
'elfparser.c',
|
||||
]
|
||||
|
||||
libelfparser_deps = [
|
||||
dependency('glib-2.0', version: glib_req_version),
|
||||
]
|
||||
|
||||
libelfparser_static = static_library('elfparser', libelfparser_sources,
|
||||
dependencies: libelfparser_deps,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
)
|
||||
|
||||
libelfparser_static_dep = declare_dependency(
|
||||
include_directories: include_directories('.'),
|
||||
dependencies: libelfparser_deps,
|
||||
link_with: libelfparser_static,
|
||||
)
|
||||
94
contrib/linereader/line-reader-private.h
Normal file
94
contrib/linereader/line-reader-private.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* line-reader-private.h
|
||||
*
|
||||
* Copyright 2015-2023 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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 <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _LineReader
|
||||
{
|
||||
char *contents;
|
||||
gsize length;
|
||||
gssize pos;
|
||||
} LineReader;
|
||||
|
||||
static inline void
|
||||
line_reader_init (LineReader *reader,
|
||||
char *contents,
|
||||
gssize length)
|
||||
{
|
||||
g_assert (reader != NULL);
|
||||
|
||||
if (length < 0)
|
||||
length = strlen (contents);
|
||||
|
||||
if (contents != NULL)
|
||||
{
|
||||
reader->contents = contents;
|
||||
reader->length = length;
|
||||
reader->pos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader->contents = NULL;
|
||||
reader->length = 0;
|
||||
reader->pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *
|
||||
line_reader_next (LineReader *reader,
|
||||
gsize *length)
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
g_assert (reader != NULL);
|
||||
g_assert (length != NULL);
|
||||
|
||||
if ((reader->contents == NULL) || (reader->pos >= reader->length))
|
||||
{
|
||||
*length = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = &reader->contents [reader->pos];
|
||||
|
||||
for (; reader->pos < reader->length; reader->pos++)
|
||||
{
|
||||
if (reader->contents [reader->pos] == '\n')
|
||||
{
|
||||
*length = &reader->contents [reader->pos] - ret;
|
||||
/* Ingore the \r in \r\n if provided */
|
||||
if (*length > 0 && reader->pos > 0 && reader->contents [reader->pos - 1] == '\r')
|
||||
(*length)--;
|
||||
reader->pos++;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*length = &reader->contents [reader->pos] - ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
7
contrib/linereader/meson.build
Normal file
7
contrib/linereader/meson.build
Normal file
@ -0,0 +1,7 @@
|
||||
liblinereader_deps = [
|
||||
dependency('gio-2.0', version: glib_req_version),
|
||||
]
|
||||
|
||||
liblinereader_static_dep = declare_dependency(
|
||||
include_directories: include_directories('.'),
|
||||
)
|
||||
3
contrib/meson.build
Normal file
3
contrib/meson.build
Normal file
@ -0,0 +1,3 @@
|
||||
subdir('eggbitset')
|
||||
subdir('elfparser')
|
||||
subdir('linereader')
|
||||
141
meson.build
141
meson.build
@ -1,9 +1,9 @@
|
||||
project('sysprof', 'c',
|
||||
project('sysprof', ['c', 'cpp'],
|
||||
license: ['GPL3+', 'GPL2+'],
|
||||
version: '45.alpha',
|
||||
meson_version: '>=0.59.0',
|
||||
default_options: [ 'c_std=gnu11',
|
||||
'cpp_std=c++11',
|
||||
default_options: [ 'c_std=gnu17',
|
||||
'cpp_std=gnu++17',
|
||||
'warning_level=2',
|
||||
]
|
||||
)
|
||||
@ -20,28 +20,48 @@ else
|
||||
app_id = 'org.gnome.Sysprof'
|
||||
endif
|
||||
|
||||
libsysprof_api_version = 4
|
||||
libsysprof_ui_api_version = 5
|
||||
# All libraries share an ABI revision as they are expected
|
||||
# to be updated as a set. However, we keep libsysprof-capture
|
||||
# at an older version since it's used as a static library
|
||||
# from various platform tooling
|
||||
soname_major_version = 6
|
||||
libsysprof_capture_api_version = 4
|
||||
libsysprof_api_version = soname_major_version
|
||||
|
||||
version_split = meson.project_version().split('.')
|
||||
datadir = get_option('datadir')
|
||||
datadir_for_pc_file = join_paths('${prefix}', datadir)
|
||||
podir = join_paths(meson.current_source_dir(), 'po')
|
||||
|
||||
glib_req = '2.73.0'
|
||||
gtk_req = '4.6'
|
||||
# Predetermine some features based on meson_options.txt
|
||||
need_gtk = get_option('gtk')
|
||||
need_glib = (need_gtk or
|
||||
get_option('examples') or
|
||||
get_option('sysprofd') != 'none' or
|
||||
get_option('tools') or
|
||||
get_option('tests'))
|
||||
need_libsysprof = (need_gtk or
|
||||
get_option('libsysprof') or
|
||||
get_option('examples') or
|
||||
get_option('tools') or
|
||||
get_option('tests'))
|
||||
|
||||
dex_req = '0.3'
|
||||
glib_req = '2.76.0'
|
||||
gtk_req = '4.10'
|
||||
polkit_req = '0.105'
|
||||
|
||||
dex_req_version = '>= @0@'.format(dex_req)
|
||||
glib_req_version = '>= @0@'.format(glib_req)
|
||||
gtk_req_version = '>= @0@'.format(gtk_req)
|
||||
polkit_req_version = '>= @0@'.format(polkit_req)
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
if get_option('libsysprof') or get_option('agent')
|
||||
add_languages('cpp', native: false)
|
||||
cxx = meson.get_compiler('cpp')
|
||||
endif
|
||||
glib_dep = dependency('glib-2.0', version: glib_req_version, required: need_glib)
|
||||
gtk_dep = dependency('gtk4', version: gtk_req_version, required: need_gtk)
|
||||
libsystemd_dep = dependency('libsystemd', required: false)
|
||||
|
||||
config_h = configuration_data()
|
||||
config_h.set_quoted('SYMBOLIC_VERSION', symbolic_version)
|
||||
@ -72,25 +92,19 @@ if get_option('default_library') != 'static'
|
||||
endif
|
||||
endif
|
||||
|
||||
debugdir = get_option('debugdir')
|
||||
if debugdir == ''
|
||||
debugdir = join_paths(get_option('prefix'), get_option('libdir'), 'debug')
|
||||
endif
|
||||
config_h.set_quoted('DEBUGDIR', debugdir)
|
||||
|
||||
config_h.set_quoted('GETTEXT_PACKAGE', 'sysprof')
|
||||
config_h.set10('ENABLE_NLS', true)
|
||||
config_h.set_quoted('PACKAGE_LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
|
||||
config_h.set('LOCALEDIR', 'PACKAGE_LOCALE_DIR')
|
||||
config_h.set('HAVE_EXECINFO_H', cc.has_header('execinfo.h'))
|
||||
|
||||
config_h.set('HAVE_STRLCPY', cc.has_function('strlcpy'))
|
||||
config_h.set('HAVE_REALLOCARRAY', cc.has_function('reallocarray'))
|
||||
config_h.set('HAVE_STRLCPY', cc.has_function('strlcpy'))
|
||||
config_h.set('LOCALEDIR', 'PACKAGE_LOCALE_DIR')
|
||||
config_h.set10('ENABLE_NLS', true)
|
||||
config_h.set_quoted('GETTEXT_PACKAGE', 'sysprof')
|
||||
config_h.set_quoted('PACKAGE_LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
|
||||
config_h.set10('HAVE_LIBSYSTEMD', libsystemd_dep.found())
|
||||
|
||||
polkit_agent_dep = dependency('polkit-agent-1', required: false)
|
||||
polkit_dep = dependency('polkit-gobject-1', version: polkit_req_version, required: false)
|
||||
|
||||
config_h.set10('HAVE_POLKIT_AGENT', polkit_agent_dep.found())
|
||||
|
||||
polkit_dep = dependency('polkit-gobject-1', version: polkit_req_version, required: false)
|
||||
config_h.set10('HAVE_POLKIT', polkit_dep.found())
|
||||
|
||||
if get_option('libunwind')
|
||||
@ -98,7 +112,11 @@ if get_option('libunwind')
|
||||
# and backtrace() showing up in builds
|
||||
libunwind_dep = dependency('libunwind-generic', required: true)
|
||||
config_h.set('ENABLE_LIBUNWIND', libunwind_dep.found())
|
||||
config_h.set('HAVE_UNW_SET_CACHE_SIZE', libunwind_dep.found() and cc.has_header_symbol('libunwind.h', 'unw_set_cache_size', dependencies: [libunwind_dep]))
|
||||
config_h.set('HAVE_UNW_SET_CACHE_SIZE',
|
||||
(libunwind_dep.found() and
|
||||
cc.has_header_symbol('libunwind.h',
|
||||
'unw_set_cache_size',
|
||||
dependencies: [libunwind_dep])))
|
||||
endif
|
||||
|
||||
# Development build setup
|
||||
@ -106,36 +124,49 @@ if get_option('development')
|
||||
config_h.set10('DEVELOPMENT_BUILD', true)
|
||||
endif
|
||||
|
||||
has_use_clockid = cc.has_member('struct perf_event_attr', 'use_clockid', prefix: '#include <linux/perf_event.h>')
|
||||
has_clockid = cc.has_member('struct perf_event_attr', 'clockid', prefix: '#include <linux/perf_event.h>')
|
||||
has_use_clockid = cc.has_member('struct perf_event_attr',
|
||||
'use_clockid',
|
||||
prefix: '#include <linux/perf_event.h>')
|
||||
has_clockid = cc.has_member('struct perf_event_attr',
|
||||
'clockid', prefix:
|
||||
'#include <linux/perf_event.h>')
|
||||
config_h.set('HAVE_PERF_CLOCKID', has_use_clockid and has_clockid)
|
||||
|
||||
add_project_arguments([
|
||||
'-I' + meson.current_build_dir(), # config.h
|
||||
], language: 'c')
|
||||
|
||||
glib_major = glib_req.split('.')[0].to_int()
|
||||
glib_minor = glib_req.split('.')[1].to_int()
|
||||
gtk_major = gtk_req.split('.')[0].to_int()
|
||||
gtk_minor = gtk_req.split('.')[1].to_int()
|
||||
|
||||
if glib_minor % 2 == 1
|
||||
glib_minor = glib_minor + 1
|
||||
endif
|
||||
if gtk_minor % 2 == 1
|
||||
gtk_minor = gtk_minor + 1
|
||||
endif
|
||||
|
||||
# For config.h
|
||||
add_project_arguments(['-I'+meson.current_build_dir()], language: 'c')
|
||||
|
||||
global_c_args = [
|
||||
'-DSYSPROF_COMPILATION',
|
||||
'-D_GNU_SOURCE',
|
||||
'-D_POSIX_C_SOURCE=200809L',
|
||||
'-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_@0@_@1@'.format(glib_major, glib_minor),
|
||||
'-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_@0@_@1@'.format(glib_major, glib_minor),
|
||||
'-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_@0@_@1@'.format(gtk_major, gtk_minor),
|
||||
'-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_@0@_@1@'.format(gtk_major, gtk_minor),
|
||||
]
|
||||
|
||||
# Enforce GLib symbol access by required version
|
||||
if need_glib
|
||||
glib_major = glib_req.split('.')[0].to_int()
|
||||
glib_minor = glib_req.split('.')[1].to_int()
|
||||
if glib_minor % 2 == 1
|
||||
glib_minor = glib_minor + 1
|
||||
endif
|
||||
global_c_args += [
|
||||
'-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_@0@_@1@'.format(glib_major, glib_minor),
|
||||
'-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_@0@_@1@'.format(glib_major, glib_minor),
|
||||
]
|
||||
endif
|
||||
|
||||
# Enforce GTK symbol access by required version
|
||||
if need_gtk
|
||||
gtk_major = gtk_req.split('.')[0].to_int()
|
||||
gtk_minor = gtk_req.split('.')[1].to_int()
|
||||
if gtk_minor % 2 == 1
|
||||
gtk_minor = gtk_minor + 1
|
||||
endif
|
||||
global_c_args += [
|
||||
'-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_@0@_@1@'.format(gtk_major, gtk_minor),
|
||||
'-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_@0@_@1@'.format(gtk_major, gtk_minor),
|
||||
]
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'darwin'
|
||||
global_c_args += ['-D_DARWIN_C_SOURCE']
|
||||
endif
|
||||
@ -155,7 +186,7 @@ test_c_args = [
|
||||
'-Wswitch-default',
|
||||
'-Wswitch-enum',
|
||||
'-Wuninitialized',
|
||||
['-Werror=format-security', '-Werror=format=2' ],
|
||||
['-Werror=format-security', '-Werror=format=2'],
|
||||
'-Werror=empty-body',
|
||||
'-Werror=implicit-function-declaration',
|
||||
'-Werror=pointer-arith',
|
||||
@ -171,13 +202,6 @@ test_c_args = [
|
||||
'-Werror=undef',
|
||||
]
|
||||
|
||||
# Until GLib is fixed with regards to volatile type registration
|
||||
if cc.get_id() == 'clang'
|
||||
test_c_args += ['-Wno-incompatible-pointer-types']
|
||||
else
|
||||
test_c_args += ['-Werror=incompatible-pointer-types']
|
||||
endif
|
||||
|
||||
foreach arg: test_c_args
|
||||
if cc.has_multi_arguments(arg)
|
||||
global_c_args += arg
|
||||
@ -229,8 +253,9 @@ int main(void) {
|
||||
config_h.set10('HAVE_STDATOMIC_H', true)
|
||||
endif
|
||||
|
||||
needs_service_access = get_option('libsysprof') or get_option('agent')
|
||||
install_service_files = needs_service_access or get_option('sysprofd') == 'bundled'
|
||||
if need_glib
|
||||
subdir('contrib')
|
||||
endif
|
||||
|
||||
subdir('src')
|
||||
subdir('data')
|
||||
|
||||
@ -8,9 +8,6 @@ option('development', type: 'boolean', value: 'false')
|
||||
# server scenarios.
|
||||
option('gtk', type: 'boolean')
|
||||
|
||||
# Disable libsysprof/ui (in situations you only want sysprof-capture)
|
||||
option('libsysprof', type: 'boolean')
|
||||
|
||||
# Allow disabling the installation of libsysprof-capture*.a
|
||||
option('install-static', type: 'boolean')
|
||||
|
||||
@ -29,18 +26,15 @@ option('systemdunitdir', type: 'string',
|
||||
description: 'Directory for systemd service files'
|
||||
)
|
||||
|
||||
# An optional location to specify where to locate debug information. This
|
||||
# is useful for distributions to set based on their debuginfo setup.
|
||||
option('debugdir', type: 'string',
|
||||
description: 'Look for global separate debug info in this path'
|
||||
)
|
||||
|
||||
# If Yelp documentation should be installed
|
||||
option('help', type: 'boolean')
|
||||
|
||||
# Disable use of libunwind
|
||||
option('libunwind', type: 'boolean')
|
||||
|
||||
# Build libsysprof (required by tools, tests, sysprof, etc)
|
||||
option('libsysprof', type: 'boolean')
|
||||
|
||||
# Optionally disable the tools (this is mostly only useful for building only
|
||||
# libsysprof-capture as a subproject)
|
||||
option('tools', type: 'boolean')
|
||||
@ -52,7 +46,3 @@ option('tests', type: 'boolean')
|
||||
# Optionally disable the examples (this is mostly only useful for building only
|
||||
# libsysprof-capture as a subproject)
|
||||
option('examples', type: 'boolean')
|
||||
|
||||
# Optionally build the sysprof-agent tool to allow profiling inside of
|
||||
# containers from external system
|
||||
option('agent', type: 'boolean', description: 'Build the sysprof-agent utility')
|
||||
|
||||
@ -98,6 +98,25 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "libdex",
|
||||
"buildsystem" : "meson",
|
||||
"config-opts" : [
|
||||
"--buildtype=debugoptimized",
|
||||
"-Ddocs=false",
|
||||
"-Dintrospection=enabled",
|
||||
"-Dexamples=false",
|
||||
"-Dtests=false",
|
||||
"-Dsysprof=false"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/chergert/libdex.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "sysprof",
|
||||
"config-opts" : [
|
||||
|
||||
@ -335,6 +335,8 @@ mapped_ring_buffer_finalize (MappedRingBuffer *self)
|
||||
close (self->fd);
|
||||
self->fd = -1;
|
||||
}
|
||||
|
||||
free (self);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -19,8 +19,11 @@ if not meson.is_subproject()
|
||||
install_headers(libsysprof_capture_headers, subdir: sysprof_header_subdir)
|
||||
endif
|
||||
|
||||
libsysprof_capture_sources = files([
|
||||
mapped_ring_buffer_sources = files([
|
||||
'mapped-ring-buffer.c',
|
||||
])
|
||||
|
||||
libsysprof_capture_sources = files([
|
||||
'sysprof-address.c',
|
||||
'sysprof-capture-condition.c',
|
||||
'sysprof-capture-cursor.c',
|
||||
@ -46,8 +49,9 @@ libsysprof_capture_deps = [
|
||||
]
|
||||
|
||||
libsysprof_capture = static_library(
|
||||
'sysprof-capture-@0@'.format(libsysprof_api_version),
|
||||
libsysprof_capture_sources,
|
||||
'sysprof-capture-@0@'.format(libsysprof_capture_api_version),
|
||||
(libsysprof_capture_sources +
|
||||
mapped_ring_buffer_sources),
|
||||
|
||||
dependencies: libsysprof_capture_deps,
|
||||
c_args: [ '-DSYSPROF_CAPTURE_COMPILATION' ],
|
||||
@ -64,7 +68,7 @@ libsysprof_capture_dep = declare_dependency(
|
||||
dependencies: libsysprof_capture_deps,
|
||||
include_directories: libsysprof_capture_include_dirs,
|
||||
)
|
||||
meson.override_dependency('sysprof-capture-@0@'.format(libsysprof_api_version), libsysprof_capture_dep)
|
||||
meson.override_dependency('sysprof-capture-@0@'.format(libsysprof_capture_api_version), libsysprof_capture_dep)
|
||||
|
||||
if install_static
|
||||
pkgconfig.generate(
|
||||
@ -76,3 +80,7 @@ if install_static
|
||||
libraries_private: libsysprof_capture_deps,
|
||||
)
|
||||
endif
|
||||
|
||||
if get_option('tests')
|
||||
subdir('tests')
|
||||
endif
|
||||
|
||||
@ -175,6 +175,10 @@ sysprof_capture_cursor_foreach (SysprofCaptureCursor *self,
|
||||
delegate = READ_DELEGATE (sysprof_capture_reader_read_sample);
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_TRACE:
|
||||
delegate = READ_DELEGATE (sysprof_capture_reader_read_trace);
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_LOG:
|
||||
delegate = READ_DELEGATE (sysprof_capture_reader_read_log);
|
||||
break;
|
||||
|
||||
@ -925,6 +925,52 @@ sysprof_capture_reader_read_sample (SysprofCaptureReader *self)
|
||||
return sample;
|
||||
}
|
||||
|
||||
const SysprofCaptureTrace *
|
||||
sysprof_capture_reader_read_trace (SysprofCaptureReader *self)
|
||||
{
|
||||
SysprofCaptureTrace *trace;
|
||||
|
||||
assert (self != NULL);
|
||||
assert ((self->pos % SYSPROF_CAPTURE_ALIGN) == 0);
|
||||
assert (self->pos <= self->bufsz);
|
||||
|
||||
if (!sysprof_capture_reader_ensure_space_for (self, sizeof *trace))
|
||||
return NULL;
|
||||
|
||||
trace = (SysprofCaptureTrace *)(void *)&self->buf[self->pos];
|
||||
|
||||
sysprof_capture_reader_bswap_frame (self, &trace->frame);
|
||||
|
||||
if (trace->frame.type != SYSPROF_CAPTURE_FRAME_TRACE)
|
||||
return NULL;
|
||||
|
||||
if (trace->frame.len < sizeof *trace)
|
||||
return NULL;
|
||||
|
||||
if (self->endian != __BYTE_ORDER)
|
||||
trace->n_addrs = bswap_16 (trace->n_addrs);
|
||||
|
||||
if (trace->frame.len < (sizeof *trace + (sizeof(SysprofCaptureAddress) * trace->n_addrs)))
|
||||
return NULL;
|
||||
|
||||
if (!sysprof_capture_reader_ensure_space_for (self, trace->frame.len))
|
||||
return NULL;
|
||||
|
||||
trace = (SysprofCaptureTrace *)(void *)&self->buf[self->pos];
|
||||
|
||||
if (SYSPROF_UNLIKELY (self->endian != __BYTE_ORDER))
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < trace->n_addrs; i++)
|
||||
trace->addrs[i] = bswap_64 (trace->addrs[i]);
|
||||
}
|
||||
|
||||
self->pos += trace->frame.len;
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
const SysprofCaptureCounterDefine *
|
||||
sysprof_capture_reader_read_counter_define (SysprofCaptureReader *self)
|
||||
{
|
||||
@ -1343,7 +1389,7 @@ array_append (const char ***files,
|
||||
*files = new_files;
|
||||
}
|
||||
|
||||
(*files)[*n_files] = new_element ? strdup (new_element) : NULL;
|
||||
(*files)[*n_files] = new_element ? sysprof_strdup (new_element) : NULL;
|
||||
*n_files = *n_files + 1;
|
||||
assert (*n_files <= *n_files_allocated);
|
||||
|
||||
@ -1362,7 +1408,10 @@ array_deduplicate (const char **files,
|
||||
for (last_written = 0, next_to_read = 1; last_written <= next_to_read && next_to_read < *n_files;)
|
||||
{
|
||||
if (strcmp (files[next_to_read], files[last_written]) == 0)
|
||||
next_to_read++;
|
||||
{
|
||||
free ((char *)files[next_to_read]);
|
||||
next_to_read++;
|
||||
}
|
||||
else
|
||||
files[++last_written] = files[next_to_read++];
|
||||
}
|
||||
|
||||
@ -111,6 +111,8 @@ const SysprofCaptureProcess *sysprof_capture_reader_read_process (
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const SysprofCaptureSample *sysprof_capture_reader_read_sample (SysprofCaptureReader *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const SysprofCaptureTrace *sysprof_capture_reader_read_trace (SysprofCaptureReader *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const SysprofCaptureJitmap *sysprof_capture_reader_read_jitmap (SysprofCaptureReader *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const SysprofCaptureCounterDefine *sysprof_capture_reader_read_counter_define (SysprofCaptureReader *self);
|
||||
|
||||
@ -140,10 +140,11 @@ typedef enum
|
||||
SYSPROF_CAPTURE_FRAME_FILE_CHUNK = 13,
|
||||
SYSPROF_CAPTURE_FRAME_ALLOCATION = 14,
|
||||
SYSPROF_CAPTURE_FRAME_OVERLAY = 15,
|
||||
SYSPROF_CAPTURE_FRAME_TRACE = 16,
|
||||
} SysprofCaptureFrameType;
|
||||
|
||||
/* Not part of ABI */
|
||||
#define SYSPROF_CAPTURE_FRAME_LAST 16
|
||||
#define SYSPROF_CAPTURE_FRAME_LAST 17
|
||||
|
||||
SYSPROF_ALIGNED_BEGIN(1)
|
||||
typedef struct
|
||||
@ -225,6 +226,18 @@ typedef struct
|
||||
} SysprofCaptureSample
|
||||
SYSPROF_ALIGNED_END(1);
|
||||
|
||||
SYSPROF_ALIGNED_BEGIN(1)
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureFrame frame;
|
||||
uint32_t n_addrs : 16;
|
||||
uint32_t entering : 1;
|
||||
uint32_t padding1 : 15;
|
||||
int32_t tid;
|
||||
SysprofCaptureAddress addrs[0];
|
||||
} SysprofCaptureTrace
|
||||
SYSPROF_ALIGNED_END(1);
|
||||
|
||||
SYSPROF_ALIGNED_BEGIN(1)
|
||||
typedef struct
|
||||
{
|
||||
@ -357,6 +370,7 @@ SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureMap) == 56, "SysprofCaptureMap chan
|
||||
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureJitmap) == 28, "SysprofCaptureJitmap changed size");
|
||||
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureProcess) == 24, "SysprofCaptureProcess changed size");
|
||||
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureSample) == 32, "SysprofCaptureSample changed size");
|
||||
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureTrace) == 32, "SysprofCaptureTrace changed size");
|
||||
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureFork) == 28, "SysprofCaptureFork changed size");
|
||||
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureExit) == 24, "SysprofCaptureExit changed size");
|
||||
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureTimestamp) == 24, "SysprofCaptureTimestamp changed size");
|
||||
@ -373,6 +387,7 @@ SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureOverlay) == 32, "SysprofCaptureOver
|
||||
|
||||
SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureAllocation, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureAllocation.addrs is not aligned");
|
||||
SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureSample, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureSample.addrs is not aligned");
|
||||
SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureTrace, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureTrace.addrs is not aligned");
|
||||
|
||||
static inline int
|
||||
sysprof_capture_address_compare (SysprofCaptureAddress a,
|
||||
|
||||
@ -416,6 +416,32 @@ sysprof_capture_writer_cat (SysprofCaptureWriter *self,
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_TRACE:
|
||||
{
|
||||
const SysprofCaptureTrace *frame;
|
||||
|
||||
if (!(frame = sysprof_capture_reader_read_trace (reader)))
|
||||
goto panic;
|
||||
|
||||
{
|
||||
SysprofCaptureAddress addrs[frame->n_addrs];
|
||||
|
||||
for (unsigned int z = 0; z < frame->n_addrs; z++)
|
||||
addrs[z] = translate_table_translate (tables, TRANSLATE_ADDR, frame->addrs[z]);
|
||||
|
||||
sysprof_capture_writer_add_trace (self,
|
||||
frame->frame.time,
|
||||
frame->frame.cpu,
|
||||
frame->frame.pid,
|
||||
frame->tid,
|
||||
addrs,
|
||||
frame->n_addrs,
|
||||
frame->entering);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_CTRDEF:
|
||||
{
|
||||
const SysprofCaptureCounterDefine *frame;
|
||||
|
||||
@ -798,6 +798,42 @@ sysprof_capture_writer_add_sample (SysprofCaptureWriter *self,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sysprof_capture_writer_add_trace (SysprofCaptureWriter *self,
|
||||
int64_t time,
|
||||
int cpu,
|
||||
int32_t pid,
|
||||
int32_t tid,
|
||||
const SysprofCaptureAddress *addrs,
|
||||
unsigned int n_addrs,
|
||||
bool entering)
|
||||
{
|
||||
SysprofCaptureTrace *ev;
|
||||
size_t len;
|
||||
|
||||
assert (self != NULL);
|
||||
|
||||
len = sizeof *ev + (n_addrs * sizeof (SysprofCaptureAddress));
|
||||
|
||||
ev = (SysprofCaptureTrace *)sysprof_capture_writer_allocate (self, &len);
|
||||
if (!ev)
|
||||
return false;
|
||||
|
||||
sysprof_capture_writer_frame_init (&ev->frame,
|
||||
len,
|
||||
cpu,
|
||||
pid,
|
||||
time,
|
||||
SYSPROF_CAPTURE_FRAME_SAMPLE);
|
||||
ev->n_addrs = n_addrs;
|
||||
ev->tid = tid;
|
||||
ev->entering = !!entering;
|
||||
|
||||
memcpy (ev->addrs, addrs, (n_addrs * sizeof (SysprofCaptureAddress)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sysprof_capture_writer_add_fork (SysprofCaptureWriter *self,
|
||||
int64_t time,
|
||||
@ -1659,7 +1695,7 @@ _sysprof_capture_writer_add_raw (SysprofCaptureWriter *self,
|
||||
return false;
|
||||
|
||||
assert (fr->len == len);
|
||||
assert (fr->type < 16);
|
||||
assert (fr->type < SYSPROF_CAPTURE_FRAME_LAST);
|
||||
|
||||
memcpy (begin, fr, fr->len);
|
||||
|
||||
@ -1668,3 +1704,14 @@ _sysprof_capture_writer_add_raw (SysprofCaptureWriter *self,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
_sysprof_capture_writer_dup_fd (SysprofCaptureWriter *self)
|
||||
{
|
||||
assert (self != NULL);
|
||||
|
||||
if (self->fd == -1)
|
||||
return -1;
|
||||
|
||||
return dup (self->fd);
|
||||
}
|
||||
|
||||
@ -143,6 +143,15 @@ bool sysprof_capture_writer_add_sample (Sy
|
||||
const SysprofCaptureAddress *addrs,
|
||||
unsigned int n_addrs);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
bool sysprof_capture_writer_add_trace (SysprofCaptureWriter *self,
|
||||
int64_t time,
|
||||
int cpu,
|
||||
int32_t pid,
|
||||
int32_t tid,
|
||||
const SysprofCaptureAddress *addrs,
|
||||
unsigned int n_addrs,
|
||||
bool entering);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
bool sysprof_capture_writer_add_fork (SysprofCaptureWriter *self,
|
||||
int64_t time,
|
||||
int cpu,
|
||||
@ -235,5 +244,7 @@ SYSPROF_INTERNAL
|
||||
bool _sysprof_capture_writer_set_time_range (SysprofCaptureWriter *self,
|
||||
int64_t start_time,
|
||||
int64_t end_time) SYSPROF_INTERNAL;
|
||||
SYSPROF_INTERNAL
|
||||
int _sysprof_capture_writer_dup_fd (SysprofCaptureWriter *self);
|
||||
|
||||
SYSPROF_END_DECLS
|
||||
|
||||
@ -576,6 +576,43 @@ sysprof_collector_sample (SysprofBacktraceFunc backtrace_func,
|
||||
} COLLECTOR_END;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_collector_trace (SysprofBacktraceFunc backtrace_func,
|
||||
void *backtrace_data,
|
||||
bool entering)
|
||||
{
|
||||
COLLECTOR_BEGIN {
|
||||
SysprofCaptureTrace *ev;
|
||||
size_t len;
|
||||
|
||||
len = sizeof *ev + (sizeof (SysprofCaptureTrace) * MAX_UNWIND_DEPTH);
|
||||
|
||||
if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
|
||||
{
|
||||
int n_addrs;
|
||||
|
||||
/* See comment from sysprof_collector_allocate(). */
|
||||
if (backtrace_func)
|
||||
n_addrs = backtrace_func (ev->addrs, MAX_UNWIND_DEPTH, backtrace_data);
|
||||
else
|
||||
n_addrs = 0;
|
||||
|
||||
ev->n_addrs = ((n_addrs < 0) ? 0 : (n_addrs > MAX_UNWIND_DEPTH) ? MAX_UNWIND_DEPTH : n_addrs);
|
||||
ev->frame.len = sizeof *ev + sizeof (SysprofCaptureAddress) * ev->n_addrs;
|
||||
ev->frame.type = SYSPROF_CAPTURE_FRAME_TRACE;
|
||||
ev->frame.cpu = _do_getcpu ();
|
||||
ev->frame.pid = collector->pid;
|
||||
ev->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
|
||||
ev->tid = collector->tid;
|
||||
ev->entering = !!entering;
|
||||
ev->padding1 = 0;
|
||||
|
||||
mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
|
||||
}
|
||||
|
||||
} COLLECTOR_END;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_collector_mark (int64_t time,
|
||||
int64_t duration,
|
||||
|
||||
@ -75,6 +75,10 @@ void sysprof_collector_allocate (SysprofCaptureAddress
|
||||
SYSPROF_AVAILABLE_IN_3_36
|
||||
void sysprof_collector_sample (SysprofBacktraceFunc backtrace_func,
|
||||
void *backtrace_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_collector_trace (SysprofBacktraceFunc backtrace_func,
|
||||
void *backtrace_data,
|
||||
bool entering);
|
||||
SYSPROF_AVAILABLE_IN_3_36
|
||||
void sysprof_collector_mark (int64_t time,
|
||||
int64_t duration,
|
||||
|
||||
@ -24,8 +24,8 @@
|
||||
#include <glib/gi18n.h>
|
||||
#include <locale.h>
|
||||
#include <stddef.h>
|
||||
#include <rax.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -23,8 +23,8 @@
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <stddef.h>
|
||||
#include <rax.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
40
src/libsysprof-capture/tests/meson.build
Normal file
40
src/libsysprof-capture/tests/meson.build
Normal file
@ -0,0 +1,40 @@
|
||||
libsysprof_capture_test_env = [
|
||||
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
|
||||
'G_DEBUG=gc-friendly',
|
||||
'GSETTINGS_BACKEND=memory',
|
||||
'MALLOC_CHECK_=2',
|
||||
'NO_AT_BRIDGE=1',
|
||||
]
|
||||
|
||||
libsysprof_capture_testsuite_c_args = [
|
||||
'-DSYSPROF_COMPILATION',
|
||||
'-DG_ENABLE_DEBUG',
|
||||
'-UG_DISABLE_ASSERT',
|
||||
'-UG_DISABLE_CAST_CHECKS',
|
||||
]
|
||||
|
||||
libsysprof_capture_testsuite = {
|
||||
'allocs-by-size' : {'skip': true},
|
||||
'cross-thread-frees' : {'skip': true},
|
||||
'find-temp-allocs' : {'skip': true},
|
||||
'rewrite-pid' : {'skip': true},
|
||||
'test-capture' : {},
|
||||
'test-capture-cursor' : {},
|
||||
'test-mapped-ring-buffer' : {},
|
||||
}
|
||||
|
||||
libsysprof_capture_testsuite_deps = [
|
||||
dependency('gio-2.0'),
|
||||
libsysprof_capture_dep,
|
||||
]
|
||||
|
||||
foreach test, params: libsysprof_capture_testsuite
|
||||
test_exe = executable(test, '@0@.c'.format(test),
|
||||
c_args: libsysprof_capture_testsuite_c_args,
|
||||
dependencies: libsysprof_capture_testsuite_deps,
|
||||
)
|
||||
if not params.get('skip', false)
|
||||
test(test, test_exe, env: libsysprof_capture_test_env)
|
||||
endif
|
||||
endforeach
|
||||
@ -732,7 +732,7 @@ test_reader_writer_file (void)
|
||||
g_autofree gchar *data = NULL;
|
||||
g_autofree gchar *testfile = NULL;
|
||||
GByteArray *buf = g_byte_array_new ();
|
||||
g_autofree const gchar **files = NULL;
|
||||
const char **files;
|
||||
SysprofCaptureWriter *writer;
|
||||
SysprofCaptureReader *reader;
|
||||
SysprofCaptureFrameType type;
|
||||
@ -799,6 +799,7 @@ test_reader_writer_file (void)
|
||||
g_assert_nonnull (files);
|
||||
g_assert_cmpstr (files[0], ==, testfile);
|
||||
g_assert_null (files[1]);
|
||||
free (files);
|
||||
|
||||
sysprof_capture_reader_reset (reader);
|
||||
new_fd = sysprof_memfd_create ("[sysprof-capture-file]");
|
||||
@ -163,6 +163,9 @@ test_threaded_movements (void)
|
||||
|
||||
g_thread_join (thread1);
|
||||
g_thread_join (thread2);
|
||||
|
||||
mapped_ring_buffer_unref (writer);
|
||||
mapped_ring_buffer_unref (reader);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -183,6 +186,8 @@ test_readwrite (void)
|
||||
mapped_ring_buffer_advance (ring, sizeof *ptr);
|
||||
}
|
||||
mapped_ring_buffer_drain (ring, drain_count_cb, NULL);
|
||||
|
||||
mapped_ring_buffer_unref (ring);
|
||||
}
|
||||
|
||||
gint
|
||||
@ -1,86 +0,0 @@
|
||||
SysprofVisualizer {
|
||||
background: @content_view_bg;
|
||||
}
|
||||
SysprofVisualizer:not(:last-child) {
|
||||
border-bottom: 1px solid alpha(@borders, 0.3);
|
||||
}
|
||||
|
||||
SysprofVisualizerGroup {
|
||||
border-bottom: 1px solid @borders;
|
||||
}
|
||||
SysprofVisualizerGroup:last-child {
|
||||
box-shadow: 0 20px 15px 15px alpha(@borders, 0.3);
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame box.horizontal.inline-toolbar {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame viewport.visualizers {
|
||||
border-right: 1px solid @borders;
|
||||
box-shadow: 1px 1px 3px alpha(@borders, 0.5);
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame scrollbar.horizontal {
|
||||
color: mix(@theme_fg_color, @theme_selected_bg_color, 0.5);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame scrollbar.horizontal range trough {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame scrollbar.horizontal range trough slider {
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
padding: 6px;
|
||||
min-height: 14px;
|
||||
background: alpha(@content_view_bg, 0.2);
|
||||
border-radius: 3px;
|
||||
border: 2px solid @theme_selected_bg_color;
|
||||
box-shadow: inset 0 10px 5px alpha(@content_view_bg,.3),
|
||||
inset 0 -15px 5px alpha(@content_view_bg,.1),
|
||||
0px 2px 4px @borders;
|
||||
}
|
||||
|
||||
SysprofVisualizerTicks {
|
||||
color: mix(@theme_fg_color, @borders, 0.5);
|
||||
background-color: @content_view_bg;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame list {
|
||||
background-color: @theme_bg_color;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame list.visualizer-groups row {
|
||||
padding: 0;
|
||||
border-bottom: 1px solid @borders;
|
||||
}
|
||||
SysprofVisualizersFrame list.visualizer-groups row:not(:selected) {
|
||||
background-color: @theme_bg_color;
|
||||
}
|
||||
SysprofVisualizersFrame list.visualizer-groups row:last-child {
|
||||
box-shadow: 0 20px 15px 15px alpha(@borders, 0.3);
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame .left-column .small-button.flat {
|
||||
border-color: transparent;
|
||||
min-height: 8px;
|
||||
min-width: 8px;
|
||||
}
|
||||
SysprofVisualizersFrame .left-column .small-button.flat:checked,
|
||||
SysprofVisualizersFrame .left-column .small-button.flat:hover {
|
||||
border-color: @borders;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame .selection {
|
||||
border-radius: 3px;
|
||||
background-color: alpha(@theme_selected_bg_color, 0.35);
|
||||
box-shadow: inset 0 10px 5px alpha(@content_view_bg,.3),
|
||||
inset 0 -15px 5px alpha(@content_view_bg,.1),
|
||||
inset 0 0 1px 1px @theme_selected_bg_color;
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
list.environ-editor row button.flat:last-child {
|
||||
min-height: 16px;
|
||||
min-width: 16px;
|
||||
padding: 0;
|
||||
margin: 3px;
|
||||
}
|
||||
list.environ-editor row button.flat:not(:hover) {
|
||||
border-color: transparent;
|
||||
}
|
||||
list.environ-editor row button.flat image {
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
sysprofaidicon image.right.top {
|
||||
border-radius: 9999px;
|
||||
background-color: @theme_selected_bg_color;
|
||||
color: @theme_selected_fg_color;
|
||||
padding: 2px;
|
||||
margin: 0px;
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
/* egg-handle.h
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EGG_TYPE_HANDLE (egg_handle_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (EggHandle, egg_handle, EGG, HANDLE, GtkWidget)
|
||||
|
||||
GtkWidget *egg_handle_new (GtkPositionType position);
|
||||
void egg_handle_set_position (EggHandle *self,
|
||||
GtkPositionType position);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,145 +0,0 @@
|
||||
/* egg-handle.c
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "egg-handle-private.h"
|
||||
|
||||
#define EXTRA_SIZE 8
|
||||
|
||||
struct _EggHandle
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
GtkWidget *separator;
|
||||
GtkPositionType position : 3;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (EggHandle, egg_handle, GTK_TYPE_WIDGET)
|
||||
|
||||
static gboolean
|
||||
egg_handle_contains (GtkWidget *widget,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
EggHandle *self = (EggHandle *)widget;
|
||||
graphene_rect_t area;
|
||||
|
||||
g_assert (EGG_IS_HANDLE (self));
|
||||
|
||||
if (!gtk_widget_compute_bounds (GTK_WIDGET (self->separator),
|
||||
GTK_WIDGET (self),
|
||||
&area))
|
||||
return FALSE;
|
||||
|
||||
switch (self->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
area.origin.x -= EXTRA_SIZE;
|
||||
area.size.width = EXTRA_SIZE;
|
||||
break;
|
||||
|
||||
case GTK_POS_RIGHT:
|
||||
area.size.width = EXTRA_SIZE;
|
||||
break;
|
||||
|
||||
case GTK_POS_TOP:
|
||||
area.origin.y -= EXTRA_SIZE;
|
||||
area.size.height = EXTRA_SIZE;
|
||||
break;
|
||||
|
||||
case GTK_POS_BOTTOM:
|
||||
area.size.height = EXTRA_SIZE;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return graphene_rect_contains_point (&area, &GRAPHENE_POINT_INIT (x, y));
|
||||
}
|
||||
|
||||
static void
|
||||
egg_handle_dispose (GObject *object)
|
||||
{
|
||||
EggHandle *self = (EggHandle *)object;
|
||||
|
||||
g_clear_pointer (&self->separator, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (egg_handle_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_handle_class_init (EggHandleClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = egg_handle_dispose;
|
||||
|
||||
widget_class->contains = egg_handle_contains;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_handle_init (EggHandle *self)
|
||||
{
|
||||
self->separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_widget_set_parent (GTK_WIDGET (self->separator), GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
egg_handle_set_position (EggHandle *self,
|
||||
GtkPositionType position)
|
||||
{
|
||||
g_return_if_fail (EGG_IS_HANDLE (self));
|
||||
|
||||
self->position = position;
|
||||
|
||||
switch (position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
case GTK_POS_RIGHT:
|
||||
gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "col-resize");
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (self->separator), GTK_ORIENTATION_VERTICAL);
|
||||
break;
|
||||
|
||||
case GTK_POS_TOP:
|
||||
case GTK_POS_BOTTOM:
|
||||
gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "row-resize");
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (self->separator), GTK_ORIENTATION_HORIZONTAL);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
egg_handle_new (GtkPositionType position)
|
||||
{
|
||||
EggHandle *self;
|
||||
|
||||
self = g_object_new (EGG_TYPE_HANDLE, NULL);
|
||||
egg_handle_set_position (self, position);
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
/* egg-paned.h
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EGG_TYPE_PANED (egg_paned_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (EggPaned, egg_paned, EGG, PANED, GtkWidget)
|
||||
|
||||
GtkWidget *egg_paned_new (void);
|
||||
void egg_paned_append (EggPaned *self,
|
||||
GtkWidget *child);
|
||||
void egg_paned_prepend (EggPaned *self,
|
||||
GtkWidget *child);
|
||||
void egg_paned_insert (EggPaned *self,
|
||||
int position,
|
||||
GtkWidget *child);
|
||||
void egg_paned_insert_after (EggPaned *self,
|
||||
GtkWidget *child,
|
||||
GtkWidget *sibling);
|
||||
void egg_paned_remove (EggPaned *self,
|
||||
GtkWidget *child);
|
||||
guint egg_paned_get_n_children (EggPaned *self);
|
||||
GtkWidget *egg_paned_get_nth_child (EggPaned *self,
|
||||
guint nth);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,593 +0,0 @@
|
||||
/* egg-paned.c
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "egg-paned-private.h"
|
||||
#include "egg-resizer-private.h"
|
||||
|
||||
struct _EggPaned
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
GtkOrientation orientation;
|
||||
};
|
||||
|
||||
static void buildable_iface_init (GtkBuildableIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (EggPaned, egg_paned, GTK_TYPE_WIDGET,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
N_PROPS,
|
||||
|
||||
PROP_ORIENTATION,
|
||||
};
|
||||
|
||||
static void
|
||||
update_orientation (GtkWidget *widget,
|
||||
GtkOrientation orientation)
|
||||
{
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
gtk_widget_remove_css_class (widget, "vertical");
|
||||
gtk_widget_add_css_class (widget, "horizontal");
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_remove_css_class (widget, "horizontal");
|
||||
gtk_widget_add_css_class (widget, "vertical");
|
||||
}
|
||||
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (widget),
|
||||
GTK_ACCESSIBLE_PROPERTY_ORIENTATION, orientation,
|
||||
-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_paned_new:
|
||||
*
|
||||
* Create a new #EggPaned.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #EggPaned
|
||||
*/
|
||||
GtkWidget *
|
||||
egg_paned_new (void)
|
||||
{
|
||||
return g_object_new (EGG_TYPE_PANED, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_set_orientation (EggPaned *self,
|
||||
GtkOrientation orientation)
|
||||
{
|
||||
GtkPositionType pos;
|
||||
|
||||
g_assert (EGG_IS_PANED (self));
|
||||
g_assert (orientation == GTK_ORIENTATION_HORIZONTAL ||
|
||||
orientation == GTK_ORIENTATION_VERTICAL);
|
||||
|
||||
if (self->orientation == orientation)
|
||||
return;
|
||||
|
||||
self->orientation = orientation;
|
||||
|
||||
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
pos = GTK_POS_LEFT;
|
||||
else
|
||||
pos = GTK_POS_TOP;
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_last_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_prev_sibling (child))
|
||||
{
|
||||
g_assert (EGG_IS_RESIZER (child));
|
||||
|
||||
egg_resizer_set_position (EGG_RESIZER (child), pos);
|
||||
}
|
||||
|
||||
update_orientation (GTK_WIDGET (self), self->orientation);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
g_object_notify (G_OBJECT (self), "orientation");
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
EggPaned *self = (EggPaned *)widget;
|
||||
|
||||
g_assert (EGG_IS_PANED (self));
|
||||
|
||||
*minimum = 0;
|
||||
*natural = 0;
|
||||
*minimum_baseline = -1;
|
||||
*natural_baseline = -1;
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
int child_min, child_nat;
|
||||
|
||||
gtk_widget_measure (child, orientation, for_size, &child_min, &child_nat, NULL, NULL);
|
||||
|
||||
if (orientation == self->orientation)
|
||||
{
|
||||
*minimum += child_min;
|
||||
*natural += child_nat;
|
||||
}
|
||||
else
|
||||
{
|
||||
*minimum = MAX (*minimum, child_min);
|
||||
*natural = MAX (*natural, child_nat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GtkRequisition min_request;
|
||||
GtkRequisition nat_request;
|
||||
GtkAllocation alloc;
|
||||
} ChildAllocation;
|
||||
|
||||
static void
|
||||
egg_paned_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
EggPaned *self = (EggPaned *)widget;
|
||||
ChildAllocation *allocs;
|
||||
ChildAllocation *last_alloc = NULL;
|
||||
GtkOrientation orientation;
|
||||
guint n_children = 0;
|
||||
guint n_expand = 0;
|
||||
guint i;
|
||||
int extra_width = width;
|
||||
int extra_height = height;
|
||||
int expand_width;
|
||||
int expand_height;
|
||||
int x, y;
|
||||
|
||||
g_assert (EGG_IS_PANED (self));
|
||||
|
||||
GTK_WIDGET_CLASS (egg_paned_parent_class)->size_allocate (widget, width, height, baseline);
|
||||
|
||||
n_children = egg_paned_get_n_children (self);
|
||||
|
||||
if (n_children == 1)
|
||||
{
|
||||
GtkWidget *child = gtk_widget_get_first_child (widget);
|
||||
GtkAllocation alloc = { 0, 0, width, height };
|
||||
|
||||
if (gtk_widget_get_visible (child))
|
||||
{
|
||||
gtk_widget_size_allocate (child, &alloc, -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (self));
|
||||
allocs = g_newa (ChildAllocation, n_children);
|
||||
memset (allocs, 0, sizeof *allocs * n_children);
|
||||
|
||||
/* Give min size to each of the children */
|
||||
i = 0;
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child), i++)
|
||||
{
|
||||
ChildAllocation *child_alloc = &allocs[i];
|
||||
|
||||
if (!gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, height,
|
||||
&child_alloc->min_request.width,
|
||||
&child_alloc->nat_request.width,
|
||||
NULL, NULL);
|
||||
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, width,
|
||||
&child_alloc->min_request.height,
|
||||
&child_alloc->nat_request.height,
|
||||
NULL, NULL);
|
||||
|
||||
child_alloc->alloc.width = child_alloc->min_request.width;
|
||||
child_alloc->alloc.height = child_alloc->min_request.height;
|
||||
|
||||
n_expand += gtk_widget_compute_expand (child, orientation);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
extra_width -= child_alloc->alloc.width;
|
||||
child_alloc->alloc.height = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra_height -= child_alloc->alloc.height;
|
||||
child_alloc->alloc.width = width;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now try to distribute extra space for natural size */
|
||||
i = 0;
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child), i++)
|
||||
{
|
||||
ChildAllocation *child_alloc = &allocs[i];
|
||||
|
||||
if (!gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
int taken = MIN (extra_width, child_alloc->nat_request.width - child_alloc->alloc.width);
|
||||
|
||||
if (taken > 0)
|
||||
{
|
||||
child_alloc->alloc.width += taken;
|
||||
extra_width -= taken;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int taken = MIN (extra_height, child_alloc->nat_request.height - child_alloc->alloc.height);
|
||||
|
||||
if (taken > 0)
|
||||
{
|
||||
child_alloc->alloc.height += taken;
|
||||
extra_height -= taken;
|
||||
}
|
||||
}
|
||||
|
||||
last_alloc = child_alloc;
|
||||
}
|
||||
|
||||
/* Now give extra space for those that expand */
|
||||
expand_width = n_expand ? extra_width / n_expand : 0;
|
||||
expand_height = n_expand ? extra_height / n_expand : 0;
|
||||
i = n_children;
|
||||
for (GtkWidget *child = gtk_widget_get_last_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_prev_sibling (child), i--)
|
||||
{
|
||||
ChildAllocation *child_alloc = &allocs[i-1];
|
||||
|
||||
if (!gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
if (!gtk_widget_compute_expand (child, orientation))
|
||||
continue;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
child_alloc->alloc.width += expand_width;
|
||||
extra_width -= expand_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
child_alloc->alloc.height += expand_height;
|
||||
extra_height -= expand_height;
|
||||
}
|
||||
}
|
||||
|
||||
/* Give any leftover to the last visible child */
|
||||
if (last_alloc)
|
||||
{
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
last_alloc->alloc.width += extra_width;
|
||||
else
|
||||
last_alloc->alloc.height += extra_height;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child), i++)
|
||||
{
|
||||
ChildAllocation *child_alloc = &allocs[i];
|
||||
|
||||
child_alloc->alloc.x = x;
|
||||
child_alloc->alloc.y = y;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
x += child_alloc->alloc.width;
|
||||
else
|
||||
y += child_alloc->alloc.height;
|
||||
|
||||
gtk_widget_size_allocate (child, &child_alloc->alloc, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_dispose (GObject *object)
|
||||
{
|
||||
EggPaned *self = (EggPaned *)object;
|
||||
GtkWidget *child;
|
||||
|
||||
child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
while (child)
|
||||
{
|
||||
GtkWidget *next = gtk_widget_get_next_sibling (child);
|
||||
gtk_widget_unparent (child);
|
||||
child = next;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (egg_paned_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
EggPaned *self = EGG_PANED (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ORIENTATION:
|
||||
g_value_set_enum (value, self->orientation);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
EggPaned *self = EGG_PANED (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ORIENTATION:
|
||||
egg_paned_set_orientation (self, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_class_init (EggPanedClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = egg_paned_dispose;
|
||||
object_class->get_property = egg_paned_get_property;
|
||||
object_class->set_property = egg_paned_set_property;
|
||||
|
||||
widget_class->measure = egg_paned_measure;
|
||||
widget_class->size_allocate = egg_paned_size_allocate;
|
||||
|
||||
g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "eggpaned");
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_init (EggPaned *self)
|
||||
{
|
||||
self->orientation = GTK_ORIENTATION_HORIZONTAL;
|
||||
|
||||
update_orientation (GTK_WIDGET (self), self->orientation);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_update_handles (EggPaned *self)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
g_assert (EGG_IS_PANED (self));
|
||||
|
||||
for (child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
GtkWidget *handle;
|
||||
|
||||
g_assert (EGG_IS_RESIZER (child));
|
||||
|
||||
if ((handle = egg_resizer_get_handle (EGG_RESIZER (child))))
|
||||
gtk_widget_show (handle);
|
||||
}
|
||||
|
||||
if ((child = gtk_widget_get_last_child (GTK_WIDGET (self))))
|
||||
{
|
||||
GtkWidget *handle = egg_resizer_get_handle (EGG_RESIZER (child));
|
||||
gtk_widget_hide (handle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_remove (EggPaned *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
GtkWidget *resizer;
|
||||
|
||||
g_return_if_fail (EGG_IS_PANED (self));
|
||||
g_return_if_fail (GTK_IS_WIDGET (child));
|
||||
|
||||
resizer = gtk_widget_get_ancestor (child, EGG_TYPE_RESIZER);
|
||||
g_return_if_fail (resizer != NULL &&
|
||||
gtk_widget_get_parent (resizer) == GTK_WIDGET (self));
|
||||
gtk_widget_unparent (resizer);
|
||||
egg_paned_update_handles (self);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_insert (EggPaned *self,
|
||||
int position,
|
||||
GtkWidget *child)
|
||||
{
|
||||
GtkPositionType pos;
|
||||
GtkWidget *resizer;
|
||||
|
||||
g_return_if_fail (EGG_IS_PANED (self));
|
||||
g_return_if_fail (GTK_IS_WIDGET (child));
|
||||
g_return_if_fail (gtk_widget_get_parent (child) == NULL);
|
||||
|
||||
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
pos = GTK_POS_LEFT;
|
||||
else
|
||||
pos = GTK_POS_TOP;
|
||||
|
||||
resizer = egg_resizer_new (pos);
|
||||
egg_resizer_set_child (EGG_RESIZER (resizer), child);
|
||||
|
||||
if (position < 0)
|
||||
gtk_widget_insert_before (GTK_WIDGET (resizer), GTK_WIDGET (self), NULL);
|
||||
else if (position == 0)
|
||||
gtk_widget_insert_after (GTK_WIDGET (resizer), GTK_WIDGET (self), NULL);
|
||||
else
|
||||
{
|
||||
GtkWidget *sibling = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
|
||||
for (int i = position; i > 0 && sibling != NULL; i--)
|
||||
sibling = gtk_widget_get_next_sibling (sibling);
|
||||
|
||||
gtk_widget_insert_before (GTK_WIDGET (resizer), GTK_WIDGET (self), sibling);
|
||||
}
|
||||
|
||||
egg_paned_update_handles (self);
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_append (EggPaned *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
egg_paned_insert (self, -1, child);
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_prepend (EggPaned *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
egg_paned_insert (self, 0, child);
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_insert_after (EggPaned *self,
|
||||
GtkWidget *child,
|
||||
GtkWidget *sibling)
|
||||
{
|
||||
int position = 0;
|
||||
|
||||
g_return_if_fail (EGG_IS_PANED (self));
|
||||
g_return_if_fail (GTK_IS_WIDGET (child));
|
||||
g_return_if_fail (!sibling || GTK_IS_WIDGET (sibling));
|
||||
|
||||
if (sibling == NULL)
|
||||
{
|
||||
egg_paned_prepend (self, child);
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: We should reverse insert() to call this */
|
||||
|
||||
for (GtkWidget *ancestor = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
ancestor != NULL;
|
||||
ancestor = gtk_widget_get_next_sibling (ancestor))
|
||||
{
|
||||
position++;
|
||||
|
||||
if (sibling == ancestor || gtk_widget_is_ancestor (sibling, ancestor))
|
||||
break;
|
||||
}
|
||||
|
||||
egg_paned_insert (self, position, child);
|
||||
}
|
||||
|
||||
guint
|
||||
egg_paned_get_n_children (EggPaned *self)
|
||||
{
|
||||
guint count = 0;
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
egg_paned_get_nth_child (EggPaned *self,
|
||||
guint nth)
|
||||
{
|
||||
g_return_val_if_fail (EGG_IS_PANED (self), NULL);
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
g_assert (EGG_IS_RESIZER (child));
|
||||
|
||||
if (nth == 0)
|
||||
return egg_resizer_get_child (EGG_RESIZER (child));
|
||||
|
||||
nth--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_add_child (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
GObject *child,
|
||||
const char *type)
|
||||
{
|
||||
if (GTK_IS_WIDGET (child))
|
||||
egg_paned_append (EGG_PANED (buildable), GTK_WIDGET (child));
|
||||
else
|
||||
g_warning ("Cannot add child of type %s to %s",
|
||||
G_OBJECT_TYPE_NAME (child),
|
||||
G_OBJECT_TYPE_NAME (buildable));
|
||||
}
|
||||
|
||||
static void
|
||||
buildable_iface_init (GtkBuildableIface *iface)
|
||||
{
|
||||
iface->add_child = egg_paned_add_child;
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
/* egg-resizer.h
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EGG_TYPE_RESIZER (egg_resizer_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (EggResizer, egg_resizer, EGG, RESIZER, GtkWidget)
|
||||
|
||||
GtkWidget *egg_resizer_new (GtkPositionType position);
|
||||
GtkPositionType egg_resizer_get_position (EggResizer *self);
|
||||
void egg_resizer_set_position (EggResizer *self,
|
||||
GtkPositionType position);
|
||||
GtkWidget *egg_resizer_get_child (EggResizer *self);
|
||||
void egg_resizer_set_child (EggResizer *self,
|
||||
GtkWidget *child);
|
||||
GtkWidget *egg_resizer_get_handle (EggResizer *self);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,495 +0,0 @@
|
||||
/* egg-resizer.c
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "egg-handle-private.h"
|
||||
#include "egg-resizer-private.h"
|
||||
|
||||
#define HANDLE_SIZE 8
|
||||
|
||||
struct _EggResizer
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
EggHandle *handle;
|
||||
GtkWidget *child;
|
||||
|
||||
double drag_orig_size;
|
||||
double drag_position;
|
||||
|
||||
GtkPositionType position : 3;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (EggResizer, egg_resizer, GTK_TYPE_WIDGET)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CHILD,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
egg_resizer_drag_begin_cb (EggResizer *self,
|
||||
double start_x,
|
||||
double start_y,
|
||||
GtkGestureDrag *drag)
|
||||
{
|
||||
GtkAllocation child_alloc;
|
||||
GtkAllocation handle_alloc;
|
||||
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
g_assert (GTK_IS_GESTURE_DRAG (drag));
|
||||
|
||||
if (self->child == NULL)
|
||||
return;
|
||||
|
||||
switch (self->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
if (start_x > gtk_widget_get_width (GTK_WIDGET (self)) - HANDLE_SIZE)
|
||||
goto start_drag;
|
||||
break;
|
||||
|
||||
case GTK_POS_RIGHT:
|
||||
if (start_x <= HANDLE_SIZE)
|
||||
goto start_drag;
|
||||
break;
|
||||
|
||||
case GTK_POS_TOP:
|
||||
if (start_y > gtk_widget_get_height (GTK_WIDGET (self)) - HANDLE_SIZE)
|
||||
goto start_drag;
|
||||
break;
|
||||
|
||||
case GTK_POS_BOTTOM:
|
||||
if (start_y <= HANDLE_SIZE)
|
||||
goto start_drag;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (drag),
|
||||
GTK_EVENT_SEQUENCE_DENIED);
|
||||
|
||||
return;
|
||||
|
||||
start_drag:
|
||||
|
||||
gtk_widget_get_allocation (self->child, &child_alloc);
|
||||
gtk_widget_get_allocation (GTK_WIDGET (self->handle), &handle_alloc);
|
||||
|
||||
if (self->position == GTK_POS_LEFT ||
|
||||
self->position == GTK_POS_RIGHT)
|
||||
{
|
||||
self->drag_orig_size = child_alloc.width + handle_alloc.width;
|
||||
gtk_widget_set_hexpand (self->child, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->drag_orig_size = child_alloc.height + handle_alloc.height;
|
||||
gtk_widget_set_vexpand (self->child, FALSE);
|
||||
}
|
||||
|
||||
self->drag_position = self->drag_orig_size;
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_drag_update_cb (EggResizer *self,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkGestureDrag *drag)
|
||||
{
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
g_assert (GTK_IS_GESTURE_DRAG (drag));
|
||||
|
||||
if (self->position == GTK_POS_LEFT)
|
||||
self->drag_position = self->drag_orig_size + offset_x;
|
||||
else if (self->position == GTK_POS_RIGHT)
|
||||
self->drag_position = gtk_widget_get_width (GTK_WIDGET (self)) - offset_x;
|
||||
else if (self->position == GTK_POS_TOP)
|
||||
self->drag_position = self->drag_orig_size + offset_y;
|
||||
else if (self->position == GTK_POS_BOTTOM)
|
||||
self->drag_position = gtk_widget_get_height (GTK_WIDGET (self)) - offset_y;
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_drag_end_cb (EggResizer *self,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkGestureDrag *drag)
|
||||
{
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
g_assert (GTK_IS_GESTURE_DRAG (drag));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
egg_resizer_new (GtkPositionType position)
|
||||
{
|
||||
EggResizer *self;
|
||||
|
||||
self = g_object_new (EGG_TYPE_RESIZER, NULL);
|
||||
self->position = position;
|
||||
self->handle = EGG_HANDLE (egg_handle_new (position));
|
||||
gtk_widget_set_parent (GTK_WIDGET (self->handle), GTK_WIDGET (self));
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
EggResizer *self = (EggResizer *)widget;
|
||||
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
|
||||
*minimum = 0;
|
||||
*natural = 0;
|
||||
*minimum_baseline = -1;
|
||||
*natural_baseline = -1;
|
||||
|
||||
if (self->child != NULL)
|
||||
gtk_widget_measure (self->child,
|
||||
orientation,
|
||||
for_size,
|
||||
minimum, natural,
|
||||
NULL, NULL);
|
||||
|
||||
if ((orientation == GTK_ORIENTATION_HORIZONTAL &&
|
||||
(self->position == GTK_POS_LEFT ||
|
||||
self->position == GTK_POS_RIGHT)) ||
|
||||
(orientation == GTK_ORIENTATION_VERTICAL &&
|
||||
(self->position == GTK_POS_TOP ||
|
||||
self->position == GTK_POS_BOTTOM)))
|
||||
{
|
||||
int handle_min, handle_nat;
|
||||
|
||||
if (self->drag_position != 0)
|
||||
{
|
||||
if (self->drag_position > *minimum)
|
||||
*natural = self->drag_position;
|
||||
else if (self->drag_position < *minimum)
|
||||
*natural = *minimum;
|
||||
}
|
||||
|
||||
if (gtk_widget_get_visible (GTK_WIDGET (self->handle)))
|
||||
{
|
||||
gtk_widget_measure (GTK_WIDGET (self->handle),
|
||||
orientation, for_size,
|
||||
&handle_min, &handle_nat,
|
||||
NULL, NULL);
|
||||
|
||||
*minimum += handle_min;
|
||||
*natural += handle_nat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
EggResizer *self = (EggResizer *)widget;
|
||||
GtkOrientation orientation;
|
||||
GtkAllocation child_alloc;
|
||||
GtkAllocation handle_alloc;
|
||||
int handle_min = 0, handle_nat = 0;
|
||||
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
|
||||
if (self->position == GTK_POS_LEFT ||
|
||||
self->position == GTK_POS_RIGHT)
|
||||
orientation = GTK_ORIENTATION_HORIZONTAL;
|
||||
else
|
||||
orientation = GTK_ORIENTATION_VERTICAL;
|
||||
|
||||
if (gtk_widget_get_visible (GTK_WIDGET (self->handle)))
|
||||
gtk_widget_measure (GTK_WIDGET (self->handle),
|
||||
orientation,
|
||||
-1,
|
||||
&handle_min, &handle_nat,
|
||||
NULL, NULL);
|
||||
|
||||
switch (self->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
handle_alloc.x = width - handle_min;
|
||||
handle_alloc.width = handle_min;
|
||||
handle_alloc.y = 0;
|
||||
handle_alloc.height = height;
|
||||
child_alloc.x = 0;
|
||||
child_alloc.y = 0;
|
||||
child_alloc.width = width - handle_min;
|
||||
child_alloc.height = height;
|
||||
break;
|
||||
|
||||
case GTK_POS_RIGHT:
|
||||
handle_alloc.x = 0;
|
||||
handle_alloc.width = handle_min;
|
||||
handle_alloc.y = 0;
|
||||
handle_alloc.height = height;
|
||||
child_alloc.x = handle_min;
|
||||
child_alloc.y = 0;
|
||||
child_alloc.width = width - handle_min;
|
||||
child_alloc.height = height;
|
||||
break;
|
||||
|
||||
case GTK_POS_TOP:
|
||||
handle_alloc.x = 0;
|
||||
handle_alloc.width = width;
|
||||
handle_alloc.y = height - handle_min;
|
||||
handle_alloc.height = handle_min;
|
||||
child_alloc.x = 0;
|
||||
child_alloc.y = 0;
|
||||
child_alloc.width = width;
|
||||
child_alloc.height = height - handle_min;
|
||||
break;
|
||||
|
||||
case GTK_POS_BOTTOM:
|
||||
handle_alloc.x = 0;
|
||||
handle_alloc.width = width;
|
||||
handle_alloc.y = 0;
|
||||
handle_alloc.height = handle_min;
|
||||
child_alloc.x = 0;
|
||||
child_alloc.y = handle_min;
|
||||
child_alloc.width = width;
|
||||
child_alloc.height = height - handle_min;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (gtk_widget_get_mapped (GTK_WIDGET (self->handle)))
|
||||
gtk_widget_size_allocate (GTK_WIDGET (self->handle), &handle_alloc, -1);
|
||||
|
||||
if (self->child != NULL &&
|
||||
gtk_widget_get_mapped (self->child))
|
||||
gtk_widget_size_allocate (self->child, &child_alloc, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_compute_expand (GtkWidget *widget,
|
||||
gboolean *hexpand,
|
||||
gboolean *vexpand)
|
||||
{
|
||||
EggResizer *self = EGG_RESIZER (widget);
|
||||
|
||||
if (self->child != NULL)
|
||||
{
|
||||
*hexpand = gtk_widget_compute_expand (self->child, GTK_ORIENTATION_HORIZONTAL);
|
||||
*vexpand = gtk_widget_compute_expand (self->child, GTK_ORIENTATION_VERTICAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
*hexpand = FALSE;
|
||||
*vexpand = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_dispose (GObject *object)
|
||||
{
|
||||
EggResizer *self = (EggResizer *)object;
|
||||
|
||||
if (self->handle)
|
||||
gtk_widget_unparent (GTK_WIDGET (self->handle));
|
||||
self->handle = NULL;
|
||||
|
||||
if (self->child)
|
||||
gtk_widget_unparent (self->child);
|
||||
self->child = NULL;
|
||||
|
||||
G_OBJECT_CLASS (egg_resizer_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
EggResizer *self = EGG_RESIZER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CHILD:
|
||||
g_value_set_object (value, egg_resizer_get_child (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
EggResizer *self = EGG_RESIZER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CHILD:
|
||||
egg_resizer_set_child (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_class_init (EggResizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = egg_resizer_dispose;
|
||||
object_class->get_property = egg_resizer_get_property;
|
||||
object_class->set_property = egg_resizer_set_property;
|
||||
|
||||
widget_class->compute_expand = egg_resizer_compute_expand;
|
||||
widget_class->measure = egg_resizer_measure;
|
||||
widget_class->size_allocate = egg_resizer_size_allocate;
|
||||
|
||||
properties [PROP_CHILD] =
|
||||
g_param_spec_object ("child",
|
||||
"Child",
|
||||
"Child",
|
||||
GTK_TYPE_WIDGET,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "eggresizer");
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_init (EggResizer *self)
|
||||
{
|
||||
GtkGesture *gesture;
|
||||
|
||||
gesture = gtk_gesture_drag_new ();
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), GTK_PHASE_CAPTURE);
|
||||
g_signal_connect_object (gesture,
|
||||
"drag-begin",
|
||||
G_CALLBACK (egg_resizer_drag_begin_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_signal_connect_object (gesture,
|
||||
"drag-update",
|
||||
G_CALLBACK (egg_resizer_drag_update_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_signal_connect_object (gesture,
|
||||
"drag-end",
|
||||
G_CALLBACK (egg_resizer_drag_end_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_resizer_get_child:
|
||||
* @self: a #EggResizer
|
||||
*
|
||||
* Gets the child widget of the resizer.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): A #GtkWidget or %NULL
|
||||
*/
|
||||
GtkWidget *
|
||||
egg_resizer_get_child (EggResizer *self)
|
||||
{
|
||||
g_return_val_if_fail (EGG_IS_RESIZER (self), NULL);
|
||||
|
||||
return self->child;
|
||||
}
|
||||
|
||||
void
|
||||
egg_resizer_set_child (EggResizer *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
g_return_if_fail (EGG_IS_RESIZER (self));
|
||||
g_return_if_fail (!child || GTK_IS_WIDGET (child));
|
||||
|
||||
if (child == self->child)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->child, gtk_widget_unparent);
|
||||
|
||||
self->child = child;
|
||||
|
||||
if (self->child != NULL)
|
||||
gtk_widget_insert_before (self->child,
|
||||
GTK_WIDGET (self),
|
||||
GTK_WIDGET (self->handle));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CHILD]);
|
||||
}
|
||||
|
||||
GtkPositionType
|
||||
egg_resizer_get_position (EggResizer *self)
|
||||
{
|
||||
g_return_val_if_fail (EGG_IS_RESIZER (self), 0);
|
||||
|
||||
return self->position;
|
||||
}
|
||||
|
||||
void
|
||||
egg_resizer_set_position (EggResizer *self,
|
||||
GtkPositionType position)
|
||||
{
|
||||
g_return_if_fail (EGG_IS_RESIZER (self));
|
||||
|
||||
if (position != self->position)
|
||||
{
|
||||
self->position = position;
|
||||
|
||||
egg_handle_set_position (self->handle, position);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
egg_resizer_get_handle (EggResizer *self)
|
||||
{
|
||||
g_return_val_if_fail (EGG_IS_RESIZER (self), NULL);
|
||||
|
||||
return GTK_WIDGET (self->handle);
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/sysprof">
|
||||
<file compressed="true">css/SysprofEnvironEditor-shared.css</file>
|
||||
<file compressed="true">css/SysprofDisplay-shared.css</file>
|
||||
<file compressed="true">css/SysprofProfilerAssistant-shared.css</file>
|
||||
|
||||
<!-- Application icons -->
|
||||
<file alias="icons/scalable/apps/org.gnome.Sysprof.svg">../../data/icons/org.gnome.Sysprof.svg</file>
|
||||
<file alias="icons/scalable/apps/org.gnome.Sysprof-symbolic.svg">../../data/icons/symbolic/apps/org.gnome.Sysprof-symbolic.svg</file>
|
||||
<file alias="icons/symbolic/apps/org.gnome.Sysprof-symbolic.svg">../../data/icons/symbolic/apps/org.gnome.Sysprof-symbolic.svg</file>
|
||||
</gresource>
|
||||
|
||||
<gresource prefix="/org/gnome/sysprof/ui">
|
||||
<file preprocess="xml-stripblanks">sysprof-aid-icon.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-callgraph-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-details-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-display.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-environ-editor-row.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-failed-state-view.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-logs-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-marks-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-memprof-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-process-model-row.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-profiler-assistant.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-recording-state-view.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-tab.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-visualizers-frame.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
@ -1,136 +0,0 @@
|
||||
libsysprof_ui_public_sources = [
|
||||
'sysprof-check.c',
|
||||
'sysprof-display.c',
|
||||
'sysprof-model-filter.c',
|
||||
'sysprof-notebook.c',
|
||||
'sysprof-page.c',
|
||||
'sysprof-process-model-row.c',
|
||||
'sysprof-visualizer.c',
|
||||
'sysprof-visualizer-group.c',
|
||||
'sysprof-zoom-manager.c',
|
||||
]
|
||||
|
||||
libsysprof_ui_private_sources = [
|
||||
'egg-handle.c',
|
||||
'egg-paned.c',
|
||||
'egg-resizer.c',
|
||||
|
||||
'pointcache.c',
|
||||
'rectangles.c',
|
||||
'sysprof-aid.c',
|
||||
'sysprof-aid-icon.c',
|
||||
'sysprof-battery-aid.c',
|
||||
'sysprof-cairo.c',
|
||||
'sysprof-callgraph-aid.c',
|
||||
'sysprof-callgraph-page.c',
|
||||
'sysprof-cell-renderer-duration.c',
|
||||
'sysprof-cell-renderer-percent.c',
|
||||
'sysprof-cell-renderer-progress.c',
|
||||
'sysprof-color-cycle.c',
|
||||
'sysprof-counters-aid.c',
|
||||
'sysprof-cpu-aid.c',
|
||||
'sysprof-depth-visualizer.c',
|
||||
'sysprof-details-page.c',
|
||||
'sysprof-diskstat-aid.c',
|
||||
'sysprof-display.c',
|
||||
'sysprof-duplex-visualizer.c',
|
||||
'sysprof-environ.c',
|
||||
'sysprof-environ-editor.c',
|
||||
'sysprof-environ-editor-row.c',
|
||||
'sysprof-environ-variable.c',
|
||||
'sysprof-failed-state-view.c',
|
||||
'sysprof-line-visualizer.c',
|
||||
'sysprof-log-model.c',
|
||||
'sysprof-logs-aid.c',
|
||||
'sysprof-logs-page.c',
|
||||
'sysprof-mark-detail.c',
|
||||
'sysprof-marks-aid.c',
|
||||
'sysprof-marks-model.c',
|
||||
'sysprof-marks-page.c',
|
||||
'sysprof-mark-visualizer.c',
|
||||
'sysprof-memory-aid.c',
|
||||
'sysprof-memprof-aid.c',
|
||||
'sysprof-memprof-page.c',
|
||||
'sysprof-memprof-visualizer.c',
|
||||
'sysprof-netdev-aid.c',
|
||||
'sysprof-procs-visualizer.c',
|
||||
'sysprof-profiler-assistant.c',
|
||||
'sysprof-proxy-aid.c',
|
||||
'sysprof-rapl-aid.c',
|
||||
'sysprof-recording-state-view.c',
|
||||
'sysprof-scrollmap.c',
|
||||
'sysprof-tab.c',
|
||||
'sysprof-theme-manager.c',
|
||||
'sysprof-time-label.c',
|
||||
'sysprof-time-visualizer.c',
|
||||
'sysprof-visualizer-group-header.c',
|
||||
'sysprof-visualizers-frame.c',
|
||||
'sysprof-visualizer-ticks.c',
|
||||
'../stackstash.c',
|
||||
]
|
||||
|
||||
libsysprof_ui_public_headers = [
|
||||
'sysprof-check.h',
|
||||
'sysprof-display.h',
|
||||
'sysprof-model-filter.h',
|
||||
'sysprof-notebook.h',
|
||||
'sysprof-page.h',
|
||||
'sysprof-process-model-row.h',
|
||||
'sysprof-visualizer.h',
|
||||
'sysprof-visualizer-group.h',
|
||||
'sysprof-zoom-manager.h',
|
||||
'sysprof-ui.h',
|
||||
]
|
||||
|
||||
libsysprof_ui_resources = gnome.compile_resources(
|
||||
'libsysprof-ui-resources',
|
||||
'libsysprof-ui.gresource.xml',
|
||||
c_name: 'lisysprof_ui',
|
||||
)
|
||||
|
||||
# Subset of dependencies used in generating the pkg-config file
|
||||
libsysprof_ui_pkg_deps = [
|
||||
dependency('gio-2.0', version: glib_req_version),
|
||||
dependency('gtk4', version: gtk_req_version),
|
||||
dependency('libadwaita-1'),
|
||||
]
|
||||
|
||||
libsysprof_ui_deps = libsysprof_ui_pkg_deps + [
|
||||
libsysprof_dep,
|
||||
]
|
||||
|
||||
# Meson's pkgconfig module wants to see a library here, not an internal
|
||||
# dependency object
|
||||
libsysprof_ui_pkg_deps += libsysprof
|
||||
|
||||
libsysprof_ui = shared_library(
|
||||
'sysprof-ui-@0@'.format(libsysprof_ui_api_version),
|
||||
libsysprof_ui_public_sources + libsysprof_ui_private_sources + libsysprof_ui_resources,
|
||||
|
||||
dependencies: libsysprof_ui_deps + [librax_dep],
|
||||
install_dir: get_option('libdir'),
|
||||
install: true,
|
||||
c_args: [ '-DSYSPROF_UI_COMPILATION' ],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
)
|
||||
|
||||
libsysprof_ui_dep = declare_dependency(
|
||||
link_with: libsysprof_ui,
|
||||
dependencies: libsysprof_ui_deps,
|
||||
include_directories: include_directories('.'),
|
||||
)
|
||||
meson.override_dependency('sysprof-ui-@0@'.format(libsysprof_api_version), libsysprof_ui_dep)
|
||||
|
||||
pkgconfig.generate(
|
||||
libsysprof_ui,
|
||||
subdirs: [ sysprof_ui_header_subdir ],
|
||||
description: 'The UI library for GTK applications embedding sysprof',
|
||||
install_dir: join_paths(get_option('libdir'), 'pkgconfig'),
|
||||
requires: [ 'gio-2.0', 'gtk4' ],
|
||||
libraries_private: libsysprof_ui_pkg_deps,
|
||||
variables: [
|
||||
'datadir=' + datadir_for_pc_file,
|
||||
],
|
||||
)
|
||||
|
||||
install_headers(libsysprof_ui_public_headers, subdir: sysprof_ui_header_subdir)
|
||||
@ -1,116 +0,0 @@
|
||||
/* pointcache.c
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "pointcache"
|
||||
|
||||
#include "pointcache.h"
|
||||
|
||||
struct _PointCache
|
||||
{
|
||||
volatile gint ref_count;
|
||||
GHashTable *sets;
|
||||
};
|
||||
|
||||
static void
|
||||
point_cache_finalize (PointCache *self)
|
||||
{
|
||||
g_clear_pointer (&self->sets, g_hash_table_unref);
|
||||
g_slice_free (PointCache, self);
|
||||
}
|
||||
|
||||
PointCache *
|
||||
point_cache_ref (PointCache *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
g_return_val_if_fail (self->ref_count > 0, NULL);
|
||||
|
||||
g_atomic_int_inc (&self->ref_count);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
point_cache_unref (PointCache *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->ref_count > 0);
|
||||
|
||||
if (g_atomic_int_dec_and_test (&self->ref_count))
|
||||
point_cache_finalize (self);
|
||||
}
|
||||
|
||||
PointCache *
|
||||
point_cache_new (void)
|
||||
{
|
||||
PointCache *self;
|
||||
|
||||
self = g_slice_new0 (PointCache);
|
||||
self->ref_count = 1;
|
||||
self->sets = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_array_unref);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
point_cache_add_set (PointCache *self,
|
||||
guint set_id)
|
||||
{
|
||||
g_hash_table_insert (self->sets,
|
||||
GUINT_TO_POINTER (set_id),
|
||||
g_array_new (FALSE, FALSE, sizeof (Point)));
|
||||
}
|
||||
|
||||
gboolean
|
||||
point_cache_contains_set (PointCache *self,
|
||||
guint set_id)
|
||||
{
|
||||
return g_hash_table_contains (self->sets, GUINT_TO_POINTER (set_id));
|
||||
}
|
||||
|
||||
void
|
||||
point_cache_add_point_to_set (PointCache *self,
|
||||
guint set_id,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
GArray *ar;
|
||||
Point point = { x, y };
|
||||
|
||||
ar = g_hash_table_lookup (self->sets, GUINT_TO_POINTER (set_id));
|
||||
g_array_append_val (ar, point);
|
||||
}
|
||||
|
||||
const Point *
|
||||
point_cache_get_points (PointCache *self,
|
||||
guint set_id,
|
||||
guint *n_points)
|
||||
{
|
||||
GArray *ar;
|
||||
|
||||
*n_points = 0;
|
||||
|
||||
if ((ar = g_hash_table_lookup (self->sets, GUINT_TO_POINTER (set_id))))
|
||||
{
|
||||
*n_points = ar->len;
|
||||
return &g_array_index (ar, const Point, 0);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/* pointcache.h
|
||||
*
|
||||
* Copyright 2016-2019 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 <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _PointCache PointCache;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
} Point;
|
||||
|
||||
PointCache *point_cache_new (void);
|
||||
PointCache *point_cache_ref (PointCache *self);
|
||||
void point_cache_unref (PointCache *self);
|
||||
void point_cache_add_set (PointCache *self,
|
||||
guint set_id);
|
||||
gboolean point_cache_contains_set (PointCache *self,
|
||||
guint set_id);
|
||||
void point_cache_add_point_to_set (PointCache *self,
|
||||
guint set_id,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
const Point *point_cache_get_points (PointCache *self,
|
||||
guint set_id,
|
||||
guint *n_points);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (PointCache, point_cache_unref)
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,248 +0,0 @@
|
||||
/* rectangles.c
|
||||
*
|
||||
* Copyright 2018-2019 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
|
||||
*/
|
||||
|
||||
#include "rectangles.h"
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-visualizer.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar *name;
|
||||
const gchar *message;
|
||||
gint64 begin;
|
||||
gint64 end;
|
||||
GdkRectangle area;
|
||||
} Rectangle;
|
||||
|
||||
struct _Rectangles
|
||||
{
|
||||
GStringChunk *strings;
|
||||
GArray *rectangles;
|
||||
GHashTable *y_indexes;
|
||||
GHashTable *colors;
|
||||
SysprofColorCycle *cycle;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
guint sorted : 1;
|
||||
};
|
||||
|
||||
Rectangles *
|
||||
rectangles_new (gint64 begin_time,
|
||||
gint64 end_time)
|
||||
{
|
||||
Rectangles *self;
|
||||
|
||||
self = g_slice_new0 (Rectangles);
|
||||
self->strings = g_string_chunk_new (4096);
|
||||
self->rectangles = g_array_new (FALSE, FALSE, sizeof (Rectangle));
|
||||
self->y_indexes = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
self->colors = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
|
||||
self->cycle = sysprof_color_cycle_new ();
|
||||
self->begin_time = begin_time;
|
||||
self->end_time = end_time;
|
||||
self->sorted = FALSE;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
rectangles_add (Rectangles *self,
|
||||
gint64 begin_time,
|
||||
gint64 end_time,
|
||||
const gchar *name,
|
||||
const gchar *message)
|
||||
{
|
||||
Rectangle rect = {0};
|
||||
|
||||
g_assert (self != NULL);
|
||||
|
||||
if (message != NULL)
|
||||
rect.message = g_string_chunk_insert_const (self->strings, message);
|
||||
|
||||
if (name != NULL)
|
||||
rect.name = g_string_chunk_insert_const (self->strings, name);
|
||||
|
||||
rect.begin = begin_time;
|
||||
rect.end = end_time;
|
||||
|
||||
if (rect.end == rect.begin)
|
||||
rect.area.width = 1;
|
||||
|
||||
g_array_append_val (self->rectangles, rect);
|
||||
|
||||
self->sorted = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
rectangles_free (Rectangles *self)
|
||||
{
|
||||
g_string_chunk_free (self->strings);
|
||||
g_array_unref (self->rectangles);
|
||||
g_hash_table_unref (self->colors);
|
||||
g_hash_table_unref (self->y_indexes);
|
||||
sysprof_color_cycle_unref (self->cycle);
|
||||
g_slice_free (Rectangles, self);
|
||||
}
|
||||
|
||||
static gint
|
||||
sort_rectangles (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const Rectangle *r1 = a;
|
||||
const Rectangle *r2 = b;
|
||||
gint64 r = r1->begin - r2->begin;
|
||||
if (r == 0)
|
||||
r = r1->end - r2->end;
|
||||
if (r > 0) return 1;
|
||||
else if (r < 0) return -1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rectangles_sort (Rectangles *self)
|
||||
{
|
||||
guint sequence = 0;
|
||||
|
||||
g_assert (self != NULL);
|
||||
|
||||
if (self->sorted)
|
||||
return;
|
||||
|
||||
g_array_sort (self->rectangles, sort_rectangles);
|
||||
|
||||
g_hash_table_remove_all (self->y_indexes);
|
||||
|
||||
for (guint i = 0; i < self->rectangles->len; i++)
|
||||
{
|
||||
const Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i);
|
||||
|
||||
if (!g_hash_table_contains (self->y_indexes, rect->name))
|
||||
{
|
||||
GdkRGBA rgba;
|
||||
|
||||
sysprof_color_cycle_next (self->cycle, &rgba);
|
||||
g_hash_table_insert (self->y_indexes, (gchar *)rect->name, GUINT_TO_POINTER (++sequence));
|
||||
g_hash_table_insert (self->colors, (gchar *)rect->name, g_memdup2 (&rgba, sizeof rgba));
|
||||
}
|
||||
}
|
||||
|
||||
self->sorted = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
rectangles_draw (Rectangles *self,
|
||||
GtkWidget *row,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GtkAllocation alloc;
|
||||
gdouble range;
|
||||
guint ns;
|
||||
|
||||
g_assert (self != NULL);
|
||||
g_assert (SYSPROF_IS_VISUALIZER (row));
|
||||
g_assert (cr != NULL);
|
||||
|
||||
if (!self->sorted)
|
||||
rectangles_sort (self);
|
||||
|
||||
gtk_widget_get_allocation (row, &alloc);
|
||||
ns = g_hash_table_size (self->y_indexes);
|
||||
if (ns == 0 || alloc.height == 0)
|
||||
return;
|
||||
|
||||
range = self->end_time - self->begin_time;
|
||||
|
||||
for (guint i = 0; i < self->rectangles->len; i++)
|
||||
{
|
||||
Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i);
|
||||
guint y_index = GPOINTER_TO_UINT (g_hash_table_lookup (self->y_indexes, rect->name));
|
||||
SysprofVisualizerRelativePoint in_points[2];
|
||||
SysprofVisualizerAbsolutePoint out_points[2];
|
||||
GdkRectangle r;
|
||||
GdkRGBA *rgba;
|
||||
|
||||
g_assert (y_index > 0);
|
||||
g_assert (y_index <= ns);
|
||||
|
||||
in_points[0].x = (rect->begin - self->begin_time) / range;
|
||||
in_points[0].y = (y_index - 1) / (gdouble)ns;
|
||||
in_points[1].x = (rect->end - self->begin_time) / range;
|
||||
in_points[1].y = 0;
|
||||
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (row),
|
||||
in_points, G_N_ELEMENTS (in_points),
|
||||
out_points, G_N_ELEMENTS (out_points));
|
||||
|
||||
r.height = alloc.height / (gdouble)ns;
|
||||
r.x = out_points[0].x;
|
||||
r.y = out_points[0].y - r.height;
|
||||
|
||||
if (rect->end <= rect->begin)
|
||||
r.width = 1;
|
||||
else
|
||||
r.width = MAX (1, out_points[1].x - out_points[0].x);
|
||||
|
||||
rect->area = r;
|
||||
|
||||
rgba = g_hash_table_lookup (self->colors, rect->name);
|
||||
|
||||
gdk_cairo_rectangle (cr, &r);
|
||||
gdk_cairo_set_source_rgba (cr, rgba);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rectangles_set_end_time (Rectangles *self,
|
||||
gint64 end_time)
|
||||
{
|
||||
/* We might not know the real end time until we've exhausted the stream */
|
||||
self->end_time = end_time;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rectangles_query_tooltip (Rectangles *self,
|
||||
GtkTooltip *tooltip,
|
||||
const gchar *group,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
g_assert (self != NULL);
|
||||
g_assert (GTK_IS_TOOLTIP (tooltip));
|
||||
|
||||
/* TODO: Sort, binary search, etc. */
|
||||
|
||||
for (guint i = 0; i < self->rectangles->len; i++)
|
||||
{
|
||||
const Rectangle *r = &g_array_index (self->rectangles, Rectangle, i);
|
||||
|
||||
if (r->area.x <= x &&
|
||||
r->area.y <= y &&
|
||||
r->area.x + r->area.width >= x &&
|
||||
r->area.y + r->area.height >= y)
|
||||
{
|
||||
g_autofree gchar *text = g_strdup_printf ("%s:%s: %s", group, r->name, r->message);
|
||||
gtk_tooltip_set_text (tooltip, text);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
/* rectangles.h
|
||||
*
|
||||
* Copyright 2018-2019 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>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _Rectangles Rectangles;
|
||||
|
||||
Rectangles *rectangles_new (gint64 begin_time,
|
||||
gint64 end_time);
|
||||
void rectangles_free (Rectangles *self);
|
||||
void rectangles_draw (Rectangles *self,
|
||||
GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
void rectangles_add (Rectangles *self,
|
||||
gint64 begin_time,
|
||||
gint64 end_time,
|
||||
const gchar *name,
|
||||
const gchar *message);
|
||||
void rectangles_set_end_time (Rectangles *self,
|
||||
gint64 end_time);
|
||||
gboolean rectangles_query_tooltip (Rectangles *self,
|
||||
GtkTooltip *tooltip,
|
||||
const gchar *group,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,211 +0,0 @@
|
||||
/* sysprof-aid-icon.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-aid-icon"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-aid-icon.h"
|
||||
|
||||
struct _SysprofAidIcon
|
||||
{
|
||||
GtkFlowBoxChild parent_instance;
|
||||
|
||||
SysprofAid *aid;
|
||||
|
||||
/* Template Objects */
|
||||
GtkLabel *label;
|
||||
GtkImage *image;
|
||||
GtkImage *check;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofAidIcon, sysprof_aid_icon, GTK_TYPE_FLOW_BOX_CHILD)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_AID,
|
||||
PROP_SELECTED,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
/**
|
||||
* sysprof_aid_icon_new:
|
||||
*
|
||||
* Create a new #SysprofAidIcon.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofAidIcon
|
||||
*/
|
||||
GtkWidget *
|
||||
sysprof_aid_icon_new (SysprofAid *aid)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_AID (aid), NULL);
|
||||
|
||||
return g_object_new (SYSPROF_TYPE_AID_ICON,
|
||||
"aid", aid,
|
||||
NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_aid_icon_is_selected (SysprofAidIcon *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_AID_ICON (self), FALSE);
|
||||
|
||||
return gtk_widget_get_visible (GTK_WIDGET (self->check));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_aid_icon_get_aid:
|
||||
*
|
||||
* Get the aid that is represented by the icon.
|
||||
*
|
||||
* Returns: (transfer none): a #SysprofAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_aid_icon_get_aid (SysprofAidIcon *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_AID_ICON (self), NULL);
|
||||
|
||||
return self->aid;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_set_aid (SysprofAidIcon *self,
|
||||
SysprofAid *aid)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_AID_ICON (self));
|
||||
g_return_if_fail (SYSPROF_IS_AID (aid));
|
||||
|
||||
if (g_set_object (&self->aid, aid))
|
||||
{
|
||||
GIcon *icon = sysprof_aid_get_icon (aid);
|
||||
const gchar *title = sysprof_aid_get_display_name (aid);
|
||||
|
||||
g_object_set (self->image, "gicon", icon, NULL);
|
||||
gtk_label_set_label (self->label, title);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_finalize (GObject *object)
|
||||
{
|
||||
SysprofAidIcon *self = (SysprofAidIcon *)object;
|
||||
|
||||
g_clear_object (&self->aid);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_aid_icon_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofAidIcon *self = SYSPROF_AID_ICON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_AID:
|
||||
g_value_set_object (value, sysprof_aid_icon_get_aid (self));
|
||||
break;
|
||||
|
||||
case PROP_SELECTED:
|
||||
g_value_set_boolean (value, gtk_widget_get_visible (GTK_WIDGET (self->check)));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofAidIcon *self = SYSPROF_AID_ICON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_AID:
|
||||
sysprof_aid_icon_set_aid (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_SELECTED:
|
||||
gtk_widget_set_visible (GTK_WIDGET (self->check), g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_class_init (SysprofAidIconClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_aid_icon_finalize;
|
||||
object_class->get_property = sysprof_aid_icon_get_property;
|
||||
object_class->set_property = sysprof_aid_icon_set_property;
|
||||
|
||||
properties [PROP_AID] =
|
||||
g_param_spec_object ("aid",
|
||||
"Aid",
|
||||
"The aid for the icon",
|
||||
SYSPROF_TYPE_AID,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_SELECTED] =
|
||||
g_param_spec_boolean ("selected",
|
||||
"Selected",
|
||||
"If the item is selected",
|
||||
FALSE,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "sysprofaidicon");
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-aid-icon.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, check);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, image);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, label);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_init (SysprofAidIcon *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_icon_toggle (SysprofAidIcon *self)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_AID_ICON (self));
|
||||
|
||||
gtk_widget_set_visible (GTK_WIDGET (self->check),
|
||||
!gtk_widget_get_visible (GTK_WIDGET (self->check)));
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="SysprofAidIcon" parent="GtkFlowBoxChild">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkOverlay">
|
||||
<property name="halign">center</property>
|
||||
<property name="child">
|
||||
<object class="GtkImage" id="image">
|
||||
<property name="pixel-size">48</property>
|
||||
<property name="width-request">64</property>
|
||||
<property name="icon-name">org.gnome.Sysprof-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<child type="overlay">
|
||||
<object class="GtkImage" id="check">
|
||||
<property name="pixel-size">14</property>
|
||||
<property name="icon-name">object-select-symbolic</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">start</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label">
|
||||
<property name="use-underline">1</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="wrap">1</property>
|
||||
<property name="mnemonic-widget">SysprofAidIcon</property>
|
||||
<property name="max-width-chars">12</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,353 +0,0 @@
|
||||
/* sysprof-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GPtrArray *sources;
|
||||
gchar *display_name;
|
||||
GIcon *icon;
|
||||
} SysprofAidPrivate;
|
||||
|
||||
static void buildable_iface_init (GtkBuildableIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (SysprofAid, sysprof_aid, G_TYPE_OBJECT,
|
||||
G_ADD_PRIVATE (SysprofAid)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DISPLAY_NAME,
|
||||
PROP_ICON,
|
||||
PROP_ICON_NAME,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_aid_real_present_async (SysprofAid *self,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_task_report_new_error (self, callback, user_data,
|
||||
sysprof_aid_real_present_async,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"Not supported");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_aid_real_present_finish (SysprofAid *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_finalize (GObject *object)
|
||||
{
|
||||
SysprofAid *self = (SysprofAid *)object;
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->sources, g_ptr_array_unref);
|
||||
g_clear_pointer (&priv->display_name, g_free);
|
||||
g_clear_object (&priv->icon);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_aid_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofAid *self = SYSPROF_AID (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DISPLAY_NAME:
|
||||
g_value_set_string (value, sysprof_aid_get_display_name (self));
|
||||
break;
|
||||
|
||||
case PROP_ICON:
|
||||
g_value_set_object (value, sysprof_aid_get_icon (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofAid *self = SYSPROF_AID (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DISPLAY_NAME:
|
||||
sysprof_aid_set_display_name (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_ICON:
|
||||
sysprof_aid_set_icon (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_ICON_NAME:
|
||||
sysprof_aid_set_icon_name (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_class_init (SysprofAidClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_aid_finalize;
|
||||
object_class->get_property = sysprof_aid_get_property;
|
||||
object_class->set_property = sysprof_aid_set_property;
|
||||
|
||||
klass->present_async = sysprof_aid_real_present_async;
|
||||
klass->present_finish = sysprof_aid_real_present_finish;
|
||||
|
||||
properties [PROP_DISPLAY_NAME] =
|
||||
g_param_spec_string ("display-name",
|
||||
"Display Name",
|
||||
"Display Name",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_ICON_NAME] =
|
||||
g_param_spec_string ("icon-name",
|
||||
"Icon Name",
|
||||
"Icon Name",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_ICON] =
|
||||
g_param_spec_object ("icon",
|
||||
"Icon",
|
||||
"The icon to display",
|
||||
G_TYPE_ICON,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_init (SysprofAid *self G_GNUC_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_aid_get_display_name:
|
||||
* @self: a #SysprofAid
|
||||
*
|
||||
* Gets the display name as it should be shown to the user.
|
||||
*
|
||||
* Returns: a string containing the display name
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
const gchar *
|
||||
sysprof_aid_get_display_name (SysprofAid *self)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_AID (self), NULL);
|
||||
|
||||
return priv->display_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_aid_get_icon:
|
||||
*
|
||||
* Gets the icon for the aid.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GIcon or %NULL
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
GIcon *
|
||||
sysprof_aid_get_icon (SysprofAid *self)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_AID (self), NULL);
|
||||
|
||||
return priv->icon;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_set_icon (SysprofAid *self,
|
||||
GIcon *icon)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
|
||||
if (g_set_object (&priv->icon, icon))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON]);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_set_icon_name (SysprofAid *self,
|
||||
const gchar *icon_name)
|
||||
{
|
||||
g_autoptr(GIcon) icon = NULL;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
|
||||
if (icon_name != NULL)
|
||||
icon = g_themed_icon_new (icon_name);
|
||||
|
||||
sysprof_aid_set_icon (self, icon);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_set_display_name (SysprofAid *self,
|
||||
const gchar *display_name)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
|
||||
if (g_strcmp0 (display_name, priv->display_name) != 0)
|
||||
{
|
||||
g_free (priv->display_name);
|
||||
priv->display_name = g_strdup (display_name);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DISPLAY_NAME]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
g_return_if_fail (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
if (priv->sources != NULL)
|
||||
{
|
||||
for (guint i = 0; i < priv->sources->len; i++)
|
||||
{
|
||||
SysprofSource *source = g_ptr_array_index (priv->sources, i);
|
||||
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
|
||||
if (priv->sources->len > 0)
|
||||
g_ptr_array_remove_range (priv->sources, 0, priv->sources->len);
|
||||
}
|
||||
|
||||
if (SYSPROF_AID_GET_CLASS (self)->prepare)
|
||||
SYSPROF_AID_GET_CLASS (self)->prepare (self, profiler);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_add_child (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
GObject *object,
|
||||
const gchar *type G_GNUC_UNUSED)
|
||||
{
|
||||
SysprofAid *self = (SysprofAid *)buildable;
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_AID (self));
|
||||
g_assert (GTK_IS_BUILDER (builder));
|
||||
g_assert (G_IS_OBJECT (object));
|
||||
|
||||
if (SYSPROF_IS_SOURCE (object))
|
||||
{
|
||||
if (priv->sources == NULL)
|
||||
priv->sources = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
g_ptr_array_add (priv->sources, g_object_ref (object));
|
||||
return;
|
||||
}
|
||||
|
||||
g_warning ("Unsupported child type of %s: %s",
|
||||
G_OBJECT_TYPE_NAME (self),
|
||||
G_OBJECT_TYPE_NAME (object));
|
||||
}
|
||||
|
||||
static void
|
||||
buildable_iface_init (GtkBuildableIface *iface)
|
||||
{
|
||||
iface->add_child = sysprof_aid_add_child;
|
||||
}
|
||||
|
||||
SysprofAid *
|
||||
sysprof_aid_new (const gchar *display_name,
|
||||
const gchar *icon_name)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_AID,
|
||||
"display-aid", display_name,
|
||||
"icon-name", icon_name,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_present_async (SysprofAid *self,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
g_return_if_fail (reader != NULL);
|
||||
g_return_if_fail (SYSPROF_IS_DISPLAY (display));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
SYSPROF_AID_GET_CLASS (self)->present_async (self, reader, display, cancellable, callback, user_data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_aid_present_finish (SysprofAid *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_AID (self), FALSE);
|
||||
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||||
|
||||
return SYSPROF_AID_GET_CLASS (self)->present_finish (self, result, error);
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
/* sysprof-aid.h
|
||||
*
|
||||
* Copyright 2019 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 <gio/gio.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-display.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_AID (sysprof_aid_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofAid, sysprof_aid, SYSPROF, AID, GObject)
|
||||
|
||||
struct _SysprofAidClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*prepare) (SysprofAid *self,
|
||||
SysprofProfiler *profiler);
|
||||
void (*present_async) (SysprofAid *self,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean (*present_finish) (SysprofAid *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
SysprofAid *sysprof_aid_new (const gchar *display_name,
|
||||
const gchar *icon_name);
|
||||
const gchar *sysprof_aid_get_display_name (SysprofAid *self);
|
||||
void sysprof_aid_set_display_name (SysprofAid *self,
|
||||
const gchar *display_name);
|
||||
GIcon *sysprof_aid_get_icon (SysprofAid *self);
|
||||
void sysprof_aid_set_icon (SysprofAid *self,
|
||||
GIcon *icon);
|
||||
void sysprof_aid_set_icon_name (SysprofAid *self,
|
||||
const gchar *icon_name);
|
||||
void sysprof_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler);
|
||||
void sysprof_aid_present_async (SysprofAid *self,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean sysprof_aid_present_finish (SysprofAid *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,242 +0,0 @@
|
||||
/* sysprof-battery-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-battery-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-battery-aid.h"
|
||||
#include "sysprof-line-visualizer.h"
|
||||
|
||||
struct _SysprofBatteryAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofBatteryAid, sysprof_battery_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_battery_aid_new:
|
||||
*
|
||||
* Create a new #SysprofBatteryAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofBatteryAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_battery_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_BATTERY_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
#ifdef __linux__
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_BATTERY_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_battery_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_battery_counters (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
GArray *counters = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (counters != NULL);
|
||||
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *counter = &def->counters[i];
|
||||
|
||||
if (g_strcmp0 (counter->category, "Battery Charge") == 0)
|
||||
g_array_append_vals (counters, counter, 1);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_BATTERY_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_battery_counters, counters);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_BATTERY_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_battery_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_battery_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_battery_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *group;
|
||||
guint found = 0;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"title", _("Battery Charge"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_strcmp0 (ctr->category, "Battery Charge") == 0)
|
||||
{
|
||||
g_autofree gchar *title = NULL;
|
||||
gboolean is_combined = g_str_equal (ctr->name, "Combined");
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
if (is_combined)
|
||||
title = g_strdup (_("Battery Charge (All)"));
|
||||
else
|
||||
title = g_strdup_printf ("Battery Charge (%s)", ctr->name);
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", is_combined,
|
||||
NULL);
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_visualizer_group_insert (group,
|
||||
SYSPROF_VISUALIZER (row),
|
||||
is_combined ? 0 : -1,
|
||||
!is_combined);
|
||||
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
if (found > 0)
|
||||
sysprof_display_add_group (present->display, group);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (group));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_class_init (SysprofBatteryAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_battery_aid_prepare;
|
||||
aid_class->present_async = sysprof_battery_aid_present_async;
|
||||
aid_class->present_finish = sysprof_battery_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_init (SysprofBatteryAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Battery"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "battery-low-charging-symbolic");
|
||||
}
|
||||
@ -1,71 +0,0 @@
|
||||
/* sysprof-cairo.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-ui-private.h"
|
||||
|
||||
void
|
||||
_sysprof_rounded_rectangle (cairo_t *cr,
|
||||
const GdkRectangle *rect,
|
||||
gint x_radius,
|
||||
gint y_radius)
|
||||
{
|
||||
gint x;
|
||||
gint y;
|
||||
gint width;
|
||||
gint height;
|
||||
gint x1, x2;
|
||||
gint y1, y2;
|
||||
gint xr1, xr2;
|
||||
gint yr1, yr2;
|
||||
|
||||
g_return_if_fail (cr);
|
||||
g_return_if_fail (rect);
|
||||
|
||||
x = rect->x;
|
||||
y = rect->y;
|
||||
width = rect->width;
|
||||
height = rect->height;
|
||||
|
||||
x1 = x;
|
||||
x2 = x1 + width;
|
||||
y1 = y;
|
||||
y2 = y1 + height;
|
||||
|
||||
x_radius = MIN (x_radius, width / 2.0);
|
||||
y_radius = MIN (y_radius, width / 2.0);
|
||||
|
||||
xr1 = x_radius;
|
||||
xr2 = x_radius / 2.0;
|
||||
yr1 = y_radius;
|
||||
yr2 = y_radius / 2.0;
|
||||
|
||||
cairo_move_to (cr, x1 + xr1, y1);
|
||||
cairo_line_to (cr, x2 - xr1, y1);
|
||||
cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
|
||||
cairo_line_to (cr, x2, y2 - yr1);
|
||||
cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
|
||||
cairo_line_to (cr, x1 + xr1, y2);
|
||||
cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
|
||||
cairo_line_to (cr, x1, y1 + yr1);
|
||||
cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
@ -1,275 +0,0 @@
|
||||
/* sysprof-callgraph-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-callgraph-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-callgraph-aid.h"
|
||||
#include "sysprof-callgraph-page.h"
|
||||
#include "sysprof-depth-visualizer.h"
|
||||
|
||||
struct _SysprofCallgraphAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
guint has_samples : 1;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofCallgraphAid, sysprof_callgraph_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
static void
|
||||
on_group_activated_cb (SysprofVisualizerGroup *group,
|
||||
SysprofPage *page)
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
|
||||
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
|
||||
g_assert (SYSPROF_IS_PAGE (page));
|
||||
|
||||
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
|
||||
sysprof_display_set_visible_page (display, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_aid_new:
|
||||
*
|
||||
* Create a new #SysprofCallgraphAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofCallgraphAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_callgraph_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CALLGRAPH_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
const GPid *pids;
|
||||
guint n_pids;
|
||||
|
||||
if ((pids = sysprof_profiler_get_pids (profiler, &n_pids)))
|
||||
{
|
||||
for (guint i = 0; i < n_pids; i++)
|
||||
{
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
source = sysprof_perf_source_new ();
|
||||
sysprof_perf_source_set_target_pid (SYSPROF_PERF_SOURCE (source), pids[i]);
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
source = sysprof_perf_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
discover_samples_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
Present *p = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (p != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE)
|
||||
{
|
||||
p->has_samples = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *p = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_AID (source_object));
|
||||
g_assert (p != NULL);
|
||||
g_assert (p->cursor != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
/* If we find a sample frame, then we should enable the callgraph
|
||||
* and stack visualizers.
|
||||
*/
|
||||
sysprof_capture_cursor_foreach (p->cursor, discover_samples_cb, p);
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_callgraph_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_callgraph_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_callgraph_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
Present *p;
|
||||
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
p = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if (p->has_samples)
|
||||
{
|
||||
SysprofVisualizerGroup *group;
|
||||
SysprofVisualizer *depth;
|
||||
SysprofPage *page;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"has-page", TRUE,
|
||||
"priority", -500,
|
||||
"title", _("Stack Traces"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_COMBINED);
|
||||
g_object_set (depth,
|
||||
"title", _("Stack Traces"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (group, depth, 0, FALSE);
|
||||
|
||||
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY);
|
||||
g_object_set (depth,
|
||||
"title", _("Stack Traces (In Kernel)"),
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (group, depth, 1, TRUE);
|
||||
|
||||
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_USER_ONLY);
|
||||
g_object_set (depth,
|
||||
"title", _("Stack Traces (In User)"),
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (group, depth, 2, TRUE);
|
||||
|
||||
sysprof_display_add_group (p->display, group);
|
||||
|
||||
page = g_object_new (SYSPROF_TYPE_CALLGRAPH_PAGE,
|
||||
"title", _("Callgraph"),
|
||||
"vexpand", TRUE,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
sysprof_display_add_page (p->display, page);
|
||||
sysprof_display_set_visible_page (p->display, page);
|
||||
|
||||
g_signal_connect_object (group,
|
||||
"group-activated",
|
||||
G_CALLBACK (on_group_activated_cb),
|
||||
page,
|
||||
0);
|
||||
}
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_class_init (SysprofCallgraphAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_callgraph_aid_prepare;
|
||||
aid_class->present_async = sysprof_callgraph_aid_present_async;
|
||||
aid_class->present_finish = sysprof_callgraph_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_init (SysprofCallgraphAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Callgraph"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
/* sysprof-callgraph-page.h
|
||||
*
|
||||
* Copyright 2016-2019 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 <sysprof.h>
|
||||
|
||||
#include "sysprof-page.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CALLGRAPH_PAGE (sysprof_callgraph_page_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofCallgraphPage, sysprof_callgraph_page, SYSPROF, CALLGRAPH_PAGE, SysprofPage)
|
||||
|
||||
struct _SysprofCallgraphPageClass
|
||||
{
|
||||
SysprofPageClass parent_class;
|
||||
|
||||
void (*go_previous) (SysprofCallgraphPage *self);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
GtkWidget *sysprof_callgraph_page_new (void);
|
||||
SysprofCallgraphProfile *sysprof_callgraph_page_get_profile (SysprofCallgraphPage *self);
|
||||
void sysprof_callgraph_page_set_profile (SysprofCallgraphPage *self,
|
||||
SysprofCallgraphProfile *profile);
|
||||
gchar *sysprof_callgraph_page_screenshot (SysprofCallgraphPage *self);
|
||||
guint sysprof_callgraph_page_get_n_functions (SysprofCallgraphPage *self);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,212 +0,0 @@
|
||||
<interface>
|
||||
<template class="SysprofCallgraphPage" parent="SysprofPage">
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<child>
|
||||
<object class="EggPaned" id="callgraph">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="EggPaned">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="width-request">400</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="functions_view">
|
||||
<property name="fixed-height-mode">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Functions</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="ellipsize">middle</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_self_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="callers_view">
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Callers</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="ellipsize">middle</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_self_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="descendants_view">
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Descendants</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_self_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_hits_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="title" translatable="yes">Hits</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="xalign">1.0</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">4</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwStatusPage" id="loading_state">
|
||||
<property name="icon-name">content-loading-symbolic</property>
|
||||
<property name="title" translatable="yes">Generating Callgraph</property>
|
||||
<property name="description" translatable="yes">Sysprof is busy creating the selected callgraph.</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwStatusPage" id="empty_state">
|
||||
<property name="icon-name">computer-fail-symbolic</property>
|
||||
<property name="title" translatable="yes">Not Enough Samples</property>
|
||||
<property name="description" translatable="yes">More samples are necessary to display a callgraph.</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,455 +0,0 @@
|
||||
/* sysprof-cell-renderer-duration.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-cell-renderer-duration"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-cell-renderer-duration.h"
|
||||
#include "sysprof-ui-private.h"
|
||||
#include "sysprof-zoom-manager.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 capture_begin_time;
|
||||
gint64 capture_end_time;
|
||||
gint64 capture_duration;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
gchar *text;
|
||||
SysprofZoomManager *zoom_manager;
|
||||
GdkRGBA color;
|
||||
guint color_set : 1;
|
||||
} SysprofCellRendererDurationPrivate;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_BEGIN_TIME,
|
||||
PROP_CAPTURE_BEGIN_TIME,
|
||||
PROP_CAPTURE_END_TIME,
|
||||
PROP_COLOR,
|
||||
PROP_END_TIME,
|
||||
PROP_TEXT,
|
||||
PROP_ZOOM_MANAGER,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (SysprofCellRendererDuration, sysprof_cell_renderer_duration, GTK_TYPE_CELL_RENDERER)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static inline void
|
||||
rounded_rectangle (cairo_t *cr,
|
||||
const GdkRectangle *rect,
|
||||
int x_radius,
|
||||
int y_radius)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int x1, x2;
|
||||
int y1, y2;
|
||||
int xr1, xr2;
|
||||
int yr1, yr2;
|
||||
|
||||
g_assert (cr);
|
||||
g_assert (rect);
|
||||
|
||||
x = rect->x;
|
||||
y = rect->y;
|
||||
width = rect->width;
|
||||
height = rect->height;
|
||||
|
||||
x1 = x;
|
||||
x2 = x1 + width;
|
||||
y1 = y;
|
||||
y2 = y1 + height;
|
||||
|
||||
x_radius = MIN (x_radius, width / 2.0);
|
||||
y_radius = MIN (y_radius, width / 2.0);
|
||||
|
||||
xr1 = x_radius;
|
||||
xr2 = x_radius / 2.0;
|
||||
yr1 = y_radius;
|
||||
yr2 = y_radius / 2.0;
|
||||
|
||||
cairo_move_to (cr, x1 + xr1, y1);
|
||||
cairo_line_to (cr, x2 - xr1, y1);
|
||||
cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
|
||||
cairo_line_to (cr, x2, y2 - yr1);
|
||||
cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
|
||||
cairo_line_to (cr, x1 + xr1, y2);
|
||||
cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
|
||||
cairo_line_to (cr, x1, y1 + yr1);
|
||||
cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_snapshot (GtkCellRenderer *renderer,
|
||||
GtkSnapshot *snapshot,
|
||||
GtkWidget *widget,
|
||||
const GdkRectangle *bg_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState state)
|
||||
{
|
||||
SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)renderer;
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
g_autoptr(GString) str = NULL;
|
||||
GtkStyleContext *style_context;
|
||||
cairo_t *cr;
|
||||
gdouble x1, x2;
|
||||
GdkRGBA rgba;
|
||||
GdkRectangle r;
|
||||
gint64 duration;
|
||||
|
||||
g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (self));
|
||||
g_assert (snapshot != NULL);
|
||||
g_assert (GTK_IS_WIDGET (widget));
|
||||
|
||||
if (priv->zoom_manager == NULL)
|
||||
return;
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (cell_area->x, cell_area->y, cell_area->width, cell_area->height));
|
||||
|
||||
style_context = gtk_widget_get_style_context (widget);
|
||||
|
||||
if (priv->color_set)
|
||||
rgba = priv->color;
|
||||
else
|
||||
gtk_style_context_get_color (style_context, &rgba);
|
||||
|
||||
duration = sysprof_zoom_manager_get_duration_for_width (priv->zoom_manager, bg_area->width);
|
||||
|
||||
x1 = (priv->begin_time - priv->capture_begin_time) / (gdouble)duration * cell_area->width;
|
||||
x2 = (priv->end_time - priv->capture_begin_time) / (gdouble)duration * cell_area->width;
|
||||
|
||||
if (x2 < x1)
|
||||
x2 = x1;
|
||||
|
||||
r.x = cell_area->x + x1;
|
||||
r.height = 12;
|
||||
r.y = cell_area->y + (cell_area->height - r.height) / 2;
|
||||
r.width = MAX (1.0, x2 - x1);
|
||||
|
||||
if ((cell_area->height - r.height) % 2 == 1)
|
||||
r.height++;
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
|
||||
if (r.width > 3)
|
||||
{
|
||||
rounded_rectangle (cr, &r, 2, 2);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
else if (r.width > 1)
|
||||
{
|
||||
gdk_cairo_rectangle (cr, &r);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_set_line_width (cr, 1);
|
||||
cairo_move_to (cr, r.x + .5, r.y);
|
||||
cairo_line_to (cr, r.x + .5, r.y + r.height);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
str = g_string_new (NULL);
|
||||
|
||||
if (priv->begin_time != priv->end_time)
|
||||
{
|
||||
g_autofree gchar *fmt = _sysprof_format_duration (priv->end_time - priv->begin_time);
|
||||
g_string_append_printf (str, "%s — ", fmt);
|
||||
}
|
||||
|
||||
if (priv->text != NULL)
|
||||
g_string_append (str, priv->text);
|
||||
|
||||
if (str->len)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
gint w, h;
|
||||
|
||||
/* Add some spacing before/after */
|
||||
r.x -= 24;
|
||||
r.width += 48;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, NULL);
|
||||
pango_layout_set_text (layout, str->str, str->len);
|
||||
pango_layout_get_pixel_size (layout, &w, &h);
|
||||
|
||||
if ((r.x + r.width + w) < (cell_area->x + cell_area->width) ||
|
||||
((cell_area->x + w) > r.x))
|
||||
cairo_move_to (cr, r.x + r.width, r.y + ((r.height - h) / 2));
|
||||
else
|
||||
cairo_move_to (cr, r.x - w, r.y + ((r.height - h) / 2));
|
||||
|
||||
if (priv->end_time < priv->begin_time)
|
||||
{
|
||||
gdk_rgba_parse (&rgba, "#f00");
|
||||
if (state & GTK_CELL_RENDERER_SELECTED)
|
||||
rgba.alpha = 0.6;
|
||||
}
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static GtkSizeRequestMode
|
||||
sysprof_cell_renderer_duration_get_request_mode (GtkCellRenderer *renderer)
|
||||
{
|
||||
return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_get_preferred_width (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
gint *min_width,
|
||||
gint *nat_width)
|
||||
{
|
||||
SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)cell;
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
gint width = 1;
|
||||
|
||||
g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (self));
|
||||
g_assert (GTK_IS_WIDGET (widget));
|
||||
|
||||
GTK_CELL_RENDERER_CLASS (sysprof_cell_renderer_duration_parent_class)->get_preferred_width (cell, widget, min_width, nat_width);
|
||||
|
||||
if (priv->zoom_manager && priv->capture_begin_time && priv->capture_end_time)
|
||||
width = sysprof_zoom_manager_get_width_for_duration (priv->zoom_manager,
|
||||
priv->capture_end_time - priv->capture_begin_time);
|
||||
|
||||
if (min_width)
|
||||
*min_width = width;
|
||||
|
||||
if (nat_width)
|
||||
*nat_width = width;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_get_preferred_height_for_width (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
gint width,
|
||||
gint *min_height,
|
||||
gint *nat_height)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
gint w, h;
|
||||
gint ypad;
|
||||
|
||||
g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (cell));
|
||||
|
||||
gtk_cell_renderer_get_padding (cell, NULL, &ypad);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, "XMZ09");
|
||||
pango_layout_get_pixel_size (layout, &w, &h);
|
||||
g_clear_object (&layout);
|
||||
|
||||
if (min_height)
|
||||
*min_height = h + (ypad * 2);
|
||||
|
||||
if (nat_height)
|
||||
*nat_height = h + (ypad * 2);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_finalize (GObject *object)
|
||||
{
|
||||
SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)object;
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
|
||||
g_clear_object (&priv->zoom_manager);
|
||||
g_clear_pointer (&priv->text, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_cell_renderer_duration_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererDuration *self = SYSPROF_CELL_RENDERER_DURATION (object);
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BEGIN_TIME:
|
||||
g_value_set_int64 (value, priv->begin_time);
|
||||
break;
|
||||
|
||||
case PROP_CAPTURE_BEGIN_TIME:
|
||||
g_value_set_int64 (value, priv->capture_begin_time);
|
||||
break;
|
||||
|
||||
case PROP_CAPTURE_END_TIME:
|
||||
g_value_set_int64 (value, priv->capture_end_time);
|
||||
break;
|
||||
|
||||
case PROP_END_TIME:
|
||||
g_value_set_int64 (value, priv->end_time);
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, priv->text);
|
||||
break;
|
||||
|
||||
case PROP_ZOOM_MANAGER:
|
||||
g_value_set_object (value, priv->zoom_manager);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererDuration *self = SYSPROF_CELL_RENDERER_DURATION (object);
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BEGIN_TIME:
|
||||
priv->begin_time = g_value_get_int64 (value);
|
||||
break;
|
||||
|
||||
case PROP_CAPTURE_BEGIN_TIME:
|
||||
priv->capture_begin_time = g_value_get_int64 (value);
|
||||
priv->capture_duration = priv->capture_end_time - priv->capture_begin_time;
|
||||
break;
|
||||
|
||||
case PROP_CAPTURE_END_TIME:
|
||||
priv->capture_end_time = g_value_get_int64 (value);
|
||||
priv->capture_duration = priv->capture_end_time - priv->capture_begin_time;
|
||||
break;
|
||||
|
||||
case PROP_COLOR:
|
||||
if (g_value_get_boxed (value))
|
||||
priv->color = *(GdkRGBA *)g_value_get_boxed (value);
|
||||
else
|
||||
gdk_rgba_parse (&priv->color, "#000");
|
||||
priv->color_set = !!g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_END_TIME:
|
||||
priv->end_time = g_value_get_int64 (value);
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
g_free (priv->text);
|
||||
priv->text = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_ZOOM_MANAGER:
|
||||
g_set_object (&priv->zoom_manager, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_class_init (SysprofCellRendererDurationClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_cell_renderer_duration_finalize;
|
||||
object_class->get_property = sysprof_cell_renderer_duration_get_property;
|
||||
object_class->set_property = sysprof_cell_renderer_duration_set_property;
|
||||
|
||||
cell_class->get_preferred_height_for_width = sysprof_cell_renderer_duration_get_preferred_height_for_width;
|
||||
cell_class->get_preferred_width = sysprof_cell_renderer_duration_get_preferred_width;
|
||||
cell_class->get_request_mode = sysprof_cell_renderer_duration_get_request_mode;
|
||||
cell_class->snapshot = sysprof_cell_renderer_duration_snapshot;
|
||||
|
||||
/* Note we do not emit ::notify() for these properties */
|
||||
|
||||
properties [PROP_BEGIN_TIME] =
|
||||
g_param_spec_int64 ("begin-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_CAPTURE_BEGIN_TIME] =
|
||||
g_param_spec_int64 ("capture-begin-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_CAPTURE_END_TIME] =
|
||||
g_param_spec_int64 ("capture-end-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_COLOR] =
|
||||
g_param_spec_boxed ("color", NULL, NULL,
|
||||
GDK_TYPE_RGBA,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_END_TIME] =
|
||||
g_param_spec_int64 ("end-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_END_TIME] =
|
||||
g_param_spec_int64 ("end-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_TEXT] =
|
||||
g_param_spec_string ("text", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_ZOOM_MANAGER] =
|
||||
g_param_spec_object ("zoom-manager", NULL, NULL,
|
||||
SYSPROF_TYPE_ZOOM_MANAGER,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_init (SysprofCellRendererDuration *self)
|
||||
{
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
|
||||
priv->color.alpha = 1.0;
|
||||
}
|
||||
|
||||
GtkCellRenderer *
|
||||
sysprof_cell_renderer_duration_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CELL_RENDERER_DURATION, NULL);
|
||||
}
|
||||
@ -1,139 +0,0 @@
|
||||
/* sysprof-cell-renderer-percent.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-cell-renderer-percent"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-cell-renderer-percent.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gdouble percent;
|
||||
} SysprofCellRendererPercentPrivate;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PERCENT,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (SysprofCellRendererPercent, sysprof_cell_renderer_percent, SYSPROF_TYPE_CELL_RENDERER_PROGRESS)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_percent_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererPercent *self = SYSPROF_CELL_RENDERER_PERCENT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PERCENT:
|
||||
g_value_set_double (value, sysprof_cell_renderer_percent_get_percent (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_percent_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererPercent *self = SYSPROF_CELL_RENDERER_PERCENT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PERCENT:
|
||||
sysprof_cell_renderer_percent_set_percent (self, g_value_get_double (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_percent_class_init (SysprofCellRendererPercentClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_cell_renderer_percent_get_property;
|
||||
object_class->set_property = sysprof_cell_renderer_percent_set_property;
|
||||
|
||||
properties [PROP_PERCENT] =
|
||||
g_param_spec_double ("percent",
|
||||
"Percent",
|
||||
"Percent",
|
||||
0.0,
|
||||
100.0,
|
||||
0.0,
|
||||
/* Doesn't notify to avoid signal emission */
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_percent_init (SysprofCellRendererPercent *self)
|
||||
{
|
||||
g_object_set (self, "text-xalign", 1.0f, NULL);
|
||||
}
|
||||
|
||||
gdouble
|
||||
sysprof_cell_renderer_percent_get_percent (SysprofCellRendererPercent *self)
|
||||
{
|
||||
SysprofCellRendererPercentPrivate *priv = sysprof_cell_renderer_percent_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CELL_RENDERER_PERCENT (self), 0.0);
|
||||
|
||||
return priv->percent;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_cell_renderer_percent_set_percent (SysprofCellRendererPercent *self,
|
||||
gdouble percent)
|
||||
{
|
||||
SysprofCellRendererPercentPrivate *priv = sysprof_cell_renderer_percent_get_instance_private (self);
|
||||
gchar text[8];
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_CELL_RENDERER_PERCENT (self));
|
||||
g_return_if_fail (percent >= 0.0);
|
||||
g_return_if_fail (percent <= 100.0);
|
||||
|
||||
priv->percent = percent;
|
||||
|
||||
g_snprintf (text, sizeof text, "%.2lf%%", percent);
|
||||
text [sizeof text - 1] = '\0';
|
||||
|
||||
g_object_set (self,
|
||||
"value", (guint)percent,
|
||||
"text", text,
|
||||
NULL);
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/* sysprof-cell-renderer-percent.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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 "sysprof-cell-renderer-progress.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CELL_RENDERER_PERCENT (sysprof_cell_renderer_percent_get_type())
|
||||
#define SYSPROF_CELL_RENDERER_PERCENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercent))
|
||||
#define SYSPROF_CELL_RENDERER_PERCENT_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercent const))
|
||||
#define SYSPROF_CELL_RENDERER_PERCENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercentClass))
|
||||
#define SYSPROF_IS_CELL_RENDERER_PERCENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT))
|
||||
#define SYSPROF_IS_CELL_RENDERER_PERCENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SYSPROF_TYPE_CELL_RENDERER_PERCENT))
|
||||
#define SYSPROF_CELL_RENDERER_PERCENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercentClass))
|
||||
|
||||
typedef struct _SysprofCellRendererPercent SysprofCellRendererPercent;
|
||||
typedef struct _SysprofCellRendererPercentClass SysprofCellRendererPercentClass;
|
||||
|
||||
struct _SysprofCellRendererPercent
|
||||
{
|
||||
SysprofCellRendererProgress parent;
|
||||
};
|
||||
|
||||
struct _SysprofCellRendererPercentClass
|
||||
{
|
||||
SysprofCellRendererProgressClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[4];
|
||||
};
|
||||
|
||||
GType sysprof_cell_renderer_percent_get_type (void);
|
||||
GtkCellRenderer *sysprof_cell_renderer_percent_new (void);
|
||||
gdouble sysprof_cell_renderer_percent_get_percent (SysprofCellRendererPercent *self);
|
||||
void sysprof_cell_renderer_percent_set_percent (SysprofCellRendererPercent *self,
|
||||
gdouble percent);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,712 +0,0 @@
|
||||
/* gtkcellrendererprogress.c
|
||||
* Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net>
|
||||
* heavily modified by Jörgen Scheibengruber <mfcn@gmx.de>
|
||||
* heavily modified by Marco Pesenti Gritti <marco@gnome.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2007. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sysprof-cell-renderer-progress.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_VALUE,
|
||||
PROP_TEXT,
|
||||
PROP_PULSE,
|
||||
PROP_TEXT_XALIGN,
|
||||
PROP_TEXT_YALIGN,
|
||||
PROP_ORIENTATION,
|
||||
PROP_INVERTED
|
||||
};
|
||||
|
||||
struct _SysprofCellRendererProgressPrivate
|
||||
{
|
||||
int value;
|
||||
char *text;
|
||||
char *label;
|
||||
int min_h;
|
||||
int min_w;
|
||||
int pulse;
|
||||
int offset;
|
||||
float text_xalign;
|
||||
float text_yalign;
|
||||
GtkOrientation orientation;
|
||||
gboolean inverted;
|
||||
};
|
||||
|
||||
static void sysprof_cell_renderer_progress_finalize (GObject *object);
|
||||
static void sysprof_cell_renderer_progress_get_property (GObject *object,
|
||||
guint param_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void sysprof_cell_renderer_progress_set_property (GObject *object,
|
||||
guint param_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void sysprof_cell_renderer_progress_set_value (SysprofCellRendererProgress *cellprogress,
|
||||
int value);
|
||||
static void sysprof_cell_renderer_progress_set_text (SysprofCellRendererProgress *cellprogress,
|
||||
const char *text);
|
||||
static void sysprof_cell_renderer_progress_set_pulse (SysprofCellRendererProgress *cellprogress,
|
||||
int pulse);
|
||||
static void compute_dimensions (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
const char *text,
|
||||
int *width,
|
||||
int *height);
|
||||
static void sysprof_cell_renderer_progress_snapshot (GtkCellRenderer *cell,
|
||||
GtkSnapshot *snapshot,
|
||||
GtkWidget *widget,
|
||||
const GdkRectangle *background_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (SysprofCellRendererProgress, sysprof_cell_renderer_progress, GTK_TYPE_CELL_RENDERER,
|
||||
G_ADD_PRIVATE (SysprofCellRendererProgress)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
|
||||
|
||||
static void
|
||||
recompute_label (SysprofCellRendererProgress *cellprogress)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
char *label;
|
||||
|
||||
if (priv->text)
|
||||
label = g_strdup (priv->text);
|
||||
else if (priv->pulse < 0)
|
||||
label = g_strdup_printf (C_("progress bar label", "%d %%"), priv->value);
|
||||
else
|
||||
label = NULL;
|
||||
|
||||
g_free (priv->label);
|
||||
priv->label = label;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_set_value (SysprofCellRendererProgress *cellprogress,
|
||||
int value)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
if (priv->value != value)
|
||||
{
|
||||
priv->value = value;
|
||||
recompute_label (cellprogress);
|
||||
g_object_notify (G_OBJECT (cellprogress), "value");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_set_text (SysprofCellRendererProgress *cellprogress,
|
||||
const char *text)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
char *new_text;
|
||||
|
||||
new_text = g_strdup (text);
|
||||
g_free (priv->text);
|
||||
priv->text = new_text;
|
||||
recompute_label (cellprogress);
|
||||
g_object_notify (G_OBJECT (cellprogress), "text");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_set_pulse (SysprofCellRendererProgress *cellprogress,
|
||||
int pulse)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
if (pulse != priv->pulse)
|
||||
{
|
||||
if (pulse <= 0)
|
||||
priv->offset = 0;
|
||||
else
|
||||
priv->offset = pulse;
|
||||
g_object_notify (G_OBJECT (cellprogress), "pulse");
|
||||
}
|
||||
|
||||
priv->pulse = pulse;
|
||||
recompute_label (cellprogress);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_finalize (GObject *object)
|
||||
{
|
||||
SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
g_free (priv->text);
|
||||
g_free (priv->label);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_cell_renderer_progress_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_get_property (GObject *object,
|
||||
guint param_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
switch (param_id)
|
||||
{
|
||||
case PROP_VALUE:
|
||||
g_value_set_int (value, priv->value);
|
||||
break;
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, priv->text);
|
||||
break;
|
||||
case PROP_PULSE:
|
||||
g_value_set_int (value, priv->pulse);
|
||||
break;
|
||||
case PROP_TEXT_XALIGN:
|
||||
g_value_set_float (value, priv->text_xalign);
|
||||
break;
|
||||
case PROP_TEXT_YALIGN:
|
||||
g_value_set_float (value, priv->text_yalign);
|
||||
break;
|
||||
case PROP_ORIENTATION:
|
||||
g_value_set_enum (value, priv->orientation);
|
||||
break;
|
||||
case PROP_INVERTED:
|
||||
g_value_set_boolean (value, priv->inverted);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_set_property (GObject *object,
|
||||
guint param_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
switch (param_id)
|
||||
{
|
||||
case PROP_VALUE:
|
||||
sysprof_cell_renderer_progress_set_value (cellprogress,
|
||||
g_value_get_int (value));
|
||||
break;
|
||||
case PROP_TEXT:
|
||||
sysprof_cell_renderer_progress_set_text (cellprogress,
|
||||
g_value_get_string (value));
|
||||
break;
|
||||
case PROP_PULSE:
|
||||
sysprof_cell_renderer_progress_set_pulse (cellprogress,
|
||||
g_value_get_int (value));
|
||||
break;
|
||||
case PROP_TEXT_XALIGN:
|
||||
priv->text_xalign = g_value_get_float (value);
|
||||
break;
|
||||
case PROP_TEXT_YALIGN:
|
||||
priv->text_yalign = g_value_get_float (value);
|
||||
break;
|
||||
case PROP_ORIENTATION:
|
||||
if (priv->orientation != g_value_get_enum (value))
|
||||
{
|
||||
priv->orientation = g_value_get_enum (value);
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
}
|
||||
break;
|
||||
case PROP_INVERTED:
|
||||
if (priv->inverted != g_value_get_boolean (value))
|
||||
{
|
||||
priv->inverted = g_value_get_boolean (value);
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compute_dimensions (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
const char *text,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
PangoRectangle logical_rect;
|
||||
PangoLayout *layout;
|
||||
int xpad, ypad;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, text);
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
||||
|
||||
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
|
||||
|
||||
if (width)
|
||||
*width = logical_rect.width + xpad * 2;
|
||||
|
||||
if (height)
|
||||
*height = logical_rect.height + ypad * 2;
|
||||
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_get_preferred_width (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
int *minimum,
|
||||
int *natural)
|
||||
{
|
||||
SysprofCellRendererProgress *self = SYSPROF_CELL_RENDERER_PROGRESS (cell);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (self);
|
||||
int w, h;
|
||||
int size;
|
||||
|
||||
if (priv->min_w < 0)
|
||||
{
|
||||
char *text = g_strdup_printf (C_("progress bar label", "%d %%"), 100);
|
||||
compute_dimensions (cell, widget, text,
|
||||
&priv->min_w,
|
||||
&priv->min_h);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
compute_dimensions (cell, widget, priv->label, &w, &h);
|
||||
|
||||
size = MAX (priv->min_w, w);
|
||||
|
||||
if (minimum != NULL)
|
||||
*minimum = size;
|
||||
if (natural != NULL)
|
||||
*natural = size;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_get_preferred_height (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
int *minimum,
|
||||
int *natural)
|
||||
{
|
||||
SysprofCellRendererProgress *self = SYSPROF_CELL_RENDERER_PROGRESS (cell);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (self);
|
||||
int w, h;
|
||||
int size;
|
||||
|
||||
if (priv->min_w < 0)
|
||||
{
|
||||
char *text = g_strdup_printf (C_("progress bar label", "%d %%"), 100);
|
||||
compute_dimensions (cell, widget, text,
|
||||
&priv->min_w,
|
||||
&priv->min_h);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
compute_dimensions (cell, widget, priv->label, &w, &h);
|
||||
|
||||
size = MIN (priv->min_h, h);
|
||||
|
||||
if (minimum != NULL)
|
||||
*minimum = size;
|
||||
if (natural != NULL)
|
||||
*natural = size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_bar_size (int pulse,
|
||||
int value,
|
||||
int full_size)
|
||||
{
|
||||
int bar_size;
|
||||
|
||||
if (pulse < 0)
|
||||
bar_size = full_size * MAX (0, value) / 100;
|
||||
else if (pulse == 0)
|
||||
bar_size = 0;
|
||||
else if (pulse == G_MAXINT)
|
||||
bar_size = full_size;
|
||||
else
|
||||
bar_size = MAX (2, full_size / 5);
|
||||
|
||||
return bar_size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_bar_position (int start,
|
||||
int full_size,
|
||||
int bar_size,
|
||||
int pulse,
|
||||
int offset,
|
||||
gboolean is_rtl)
|
||||
{
|
||||
int position;
|
||||
|
||||
if (pulse < 0 || pulse == 0 || pulse == G_MAXINT)
|
||||
{
|
||||
position = is_rtl ? (start + full_size - bar_size) : start;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = (is_rtl ? offset + 12 : offset) % 24;
|
||||
if (position > 12)
|
||||
position = 24 - position;
|
||||
position = start + full_size * position / 15;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_snapshot (GtkCellRenderer *cell,
|
||||
GtkSnapshot *snapshot,
|
||||
GtkWidget *widget,
|
||||
const GdkRectangle *background_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags)
|
||||
{
|
||||
SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (cell);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
GtkStyleContext *context;
|
||||
GtkBorder padding;
|
||||
PangoLayout *layout;
|
||||
PangoRectangle logical_rect;
|
||||
int x, y, w, h, x_pos, y_pos, bar_position, bar_size, start, full_size;
|
||||
int xpad, ypad;
|
||||
GdkRectangle clip;
|
||||
gboolean is_rtl;
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
|
||||
|
||||
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
|
||||
x = cell_area->x + xpad;
|
||||
y = cell_area->y + ypad;
|
||||
w = cell_area->width - xpad * 2;
|
||||
h = cell_area->height - ypad * 2;
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, "trough");
|
||||
|
||||
gtk_snapshot_render_background (snapshot, context, x, y, w, h);
|
||||
gtk_snapshot_render_frame (snapshot, context, x, y, w, h);
|
||||
|
||||
gtk_style_context_get_padding (context, &padding);
|
||||
|
||||
x += padding.left;
|
||||
y += padding.top;
|
||||
w -= padding.left + padding.right;
|
||||
h -= padding.top + padding.bottom;
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
clip.y = y;
|
||||
clip.height = h;
|
||||
|
||||
start = x;
|
||||
full_size = w;
|
||||
|
||||
bar_size = get_bar_size (priv->pulse, priv->value, full_size);
|
||||
|
||||
if (!priv->inverted)
|
||||
bar_position = get_bar_position (start, full_size, bar_size,
|
||||
priv->pulse, priv->offset, is_rtl);
|
||||
else
|
||||
bar_position = get_bar_position (start, full_size, bar_size,
|
||||
priv->pulse, priv->offset, !is_rtl);
|
||||
|
||||
clip.width = bar_size;
|
||||
clip.x = bar_position;
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.x = x;
|
||||
clip.width = w;
|
||||
|
||||
start = y;
|
||||
full_size = h;
|
||||
|
||||
bar_size = get_bar_size (priv->pulse, priv->value, full_size);
|
||||
|
||||
if (priv->inverted)
|
||||
bar_position = get_bar_position (start, full_size, bar_size,
|
||||
priv->pulse, priv->offset, TRUE);
|
||||
else
|
||||
bar_position = get_bar_position (start, full_size, bar_size,
|
||||
priv->pulse, priv->offset, FALSE);
|
||||
|
||||
clip.height = bar_size;
|
||||
clip.y = bar_position;
|
||||
}
|
||||
|
||||
if (bar_size > 0)
|
||||
{
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, "progressbar");
|
||||
|
||||
gtk_snapshot_render_background (snapshot, context, clip.x, clip.y, clip.width, clip.height);
|
||||
gtk_snapshot_render_frame (snapshot, context, clip.x, clip.y, clip.width, clip.height);
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
}
|
||||
|
||||
if (priv->label)
|
||||
{
|
||||
float text_xalign;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, priv->label);
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
||||
|
||||
if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
|
||||
text_xalign = 1.0 - priv->text_xalign;
|
||||
else
|
||||
text_xalign = priv->text_xalign;
|
||||
|
||||
x_pos = x + padding.left + text_xalign *
|
||||
(w - padding.left - padding.right - logical_rect.width);
|
||||
|
||||
y_pos = y + padding.top + priv->text_yalign *
|
||||
(h - padding.top - padding.bottom - logical_rect.height);
|
||||
|
||||
gtk_snapshot_push_clip (snapshot,
|
||||
&GRAPHENE_RECT_INIT(
|
||||
clip.x, clip.y,
|
||||
clip.width, clip.height
|
||||
));
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, "progressbar");
|
||||
|
||||
gtk_snapshot_render_layout (snapshot, context,
|
||||
x_pos, y_pos,
|
||||
layout);
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, "trough");
|
||||
|
||||
if (bar_position > start)
|
||||
{
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
clip.x = x;
|
||||
clip.width = bar_position - x;
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.y = y;
|
||||
clip.height = bar_position - y;
|
||||
}
|
||||
|
||||
gtk_snapshot_push_clip (snapshot,
|
||||
&GRAPHENE_RECT_INIT(
|
||||
clip.x, clip.y,
|
||||
clip.width, clip.height
|
||||
));
|
||||
|
||||
gtk_snapshot_render_layout (snapshot, context,
|
||||
x_pos, y_pos,
|
||||
layout);
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
if (bar_position + bar_size < start + full_size)
|
||||
{
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
clip.x = bar_position + bar_size;
|
||||
clip.width = x + w - (bar_position + bar_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.y = bar_position + bar_size;
|
||||
clip.height = y + h - (bar_position + bar_size);
|
||||
}
|
||||
|
||||
gtk_snapshot_push_clip (snapshot,
|
||||
&GRAPHENE_RECT_INIT(
|
||||
clip.x, clip.y,
|
||||
clip.width, clip.height
|
||||
));
|
||||
|
||||
gtk_snapshot_render_layout (snapshot, context,
|
||||
x_pos, y_pos,
|
||||
layout);
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
g_object_unref (layout);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_class_init (SysprofCellRendererProgressClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_cell_renderer_progress_finalize;
|
||||
object_class->get_property = sysprof_cell_renderer_progress_get_property;
|
||||
object_class->set_property = sysprof_cell_renderer_progress_set_property;
|
||||
|
||||
cell_class->get_preferred_width = sysprof_cell_renderer_progress_get_preferred_width;
|
||||
cell_class->get_preferred_height = sysprof_cell_renderer_progress_get_preferred_height;
|
||||
cell_class->snapshot = sysprof_cell_renderer_progress_snapshot;
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:value:
|
||||
*
|
||||
* The "value" property determines the percentage to which the
|
||||
* progress bar will be "filled in".
|
||||
**/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_VALUE,
|
||||
g_param_spec_int ("value",
|
||||
"Value",
|
||||
"Value of the progress bar",
|
||||
0, 100, 0,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:text:
|
||||
*
|
||||
* The "text" property determines the label which will be drawn
|
||||
* over the progress bar. Setting this property to %NULL causes the default
|
||||
* label to be displayed. Setting this property to an empty string causes
|
||||
* no label to be displayed.
|
||||
**/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_TEXT,
|
||||
g_param_spec_string ("text",
|
||||
"Text",
|
||||
"Text on the progress bar",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:pulse:
|
||||
*
|
||||
* Setting this to a non-negative value causes the cell renderer to
|
||||
* enter "activity mode", where a block bounces back and forth to
|
||||
* indicate that some progress is made, without specifying exactly how
|
||||
* much.
|
||||
*
|
||||
* Each increment of the property causes the block to move by a little
|
||||
* bit.
|
||||
*
|
||||
* To indicate that the activity has not started yet, set the property
|
||||
* to zero. To indicate completion, set the property to %G_MAXINT.
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PULSE,
|
||||
g_param_spec_int ("pulse",
|
||||
"Pulse",
|
||||
"Set this to positive values to indicate that some progress is made, but you don’t know how much.",
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:text-xalign:
|
||||
*
|
||||
* The "text-xalign" property controls the horizontal alignment of the
|
||||
* text in the progress bar. Valid values range from 0 (left) to 1
|
||||
* (right). Reserved for RTL layouts.
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_TEXT_XALIGN,
|
||||
g_param_spec_float ("text-xalign",
|
||||
"Text x alignment",
|
||||
"The horizontal text alignment, from 0 (left) to 1 (right). Reversed for RTL layouts.",
|
||||
0.0, 1.0, 0.5,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:text-yalign:
|
||||
*
|
||||
* The "text-yalign" property controls the vertical alignment of the
|
||||
* text in the progress bar. Valid values range from 0 (top) to 1
|
||||
* (bottom).
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_TEXT_YALIGN,
|
||||
g_param_spec_float ("text-yalign",
|
||||
"Text y alignment",
|
||||
"The vertical text alignment, from 0 (top) to 1 (bottom).",
|
||||
0.0, 1.0, 0.5,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_override_property (object_class,
|
||||
PROP_ORIENTATION,
|
||||
"orientation");
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_INVERTED,
|
||||
g_param_spec_boolean ("inverted",
|
||||
"Inverted",
|
||||
"Invert the direction in which the progress bar grows",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_init (SysprofCellRendererProgress *cellprogress)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
priv->value = 0;
|
||||
priv->text = NULL;
|
||||
priv->label = NULL;
|
||||
priv->min_w = -1;
|
||||
priv->min_h = -1;
|
||||
priv->pulse = -1;
|
||||
priv->offset = 0;
|
||||
|
||||
priv->text_xalign = 0.5;
|
||||
priv->text_yalign = 0.5;
|
||||
|
||||
priv->orientation = GTK_ORIENTATION_HORIZONTAL,
|
||||
priv->inverted = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_cell_renderer_progress_new:
|
||||
*
|
||||
* Creates a new `SysprofCellRendererProgress`.
|
||||
*
|
||||
* Returns: the new cell renderer
|
||||
**/
|
||||
GtkCellRenderer*
|
||||
sysprof_cell_renderer_progress_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CELL_RENDERER_PROGRESS, NULL);
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
/* gtkcellrendererprogress.h
|
||||
* Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net>
|
||||
* modified by Jörgen Scheibengruber <mfcn@gmx.de>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2004. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CELL_RENDERER_PROGRESS (sysprof_cell_renderer_progress_get_type ())
|
||||
#define SYSPROF_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PROGRESS, SysprofCellRendererProgress))
|
||||
#define SYSPROF_IS_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SYSPROF_TYPE_CELL_RENDERER_PROGRESS))
|
||||
|
||||
typedef struct _SysprofCellRendererProgress SysprofCellRendererProgress;
|
||||
typedef struct _SysprofCellRendererProgressClass SysprofCellRendererProgressClass;
|
||||
typedef struct _SysprofCellRendererProgressPrivate SysprofCellRendererProgressPrivate;
|
||||
|
||||
struct _SysprofCellRendererProgress
|
||||
{
|
||||
GtkCellRenderer parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofCellRendererProgressClass
|
||||
{
|
||||
GtkCellRendererClass parent_class;
|
||||
};
|
||||
|
||||
GType sysprof_cell_renderer_progress_get_type (void) G_GNUC_CONST;
|
||||
GtkCellRenderer *sysprof_cell_renderer_progress_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,106 +0,0 @@
|
||||
/* sysprof-check.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-check"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-check.h"
|
||||
|
||||
static void
|
||||
sysprof_check_supported_ping_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusConnection *bus = (GDBusConnection *)object;
|
||||
g_autoptr(GVariant) reply = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GTask) task = user_data;
|
||||
|
||||
g_assert (G_IS_DBUS_CONNECTION (bus));
|
||||
g_assert (G_IS_ASYNC_RESULT (result));
|
||||
g_assert (G_IS_TASK (task));
|
||||
|
||||
if (!(reply = g_dbus_connection_call_finish (bus, result, &error)))
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_check_supported_bus_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GDBusConnection) bus = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GTask) task = user_data;
|
||||
|
||||
g_assert (G_IS_ASYNC_RESULT (result));
|
||||
g_assert (G_IS_TASK (task));
|
||||
|
||||
if (!(bus = g_bus_get_finish (result, &error)))
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
else
|
||||
g_dbus_connection_call (bus,
|
||||
"org.gnome.Sysprof3",
|
||||
"/org/gnome/Sysprof3",
|
||||
"org.freedesktop.DBus.Peer",
|
||||
"Ping",
|
||||
g_variant_new ("()"),
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
g_task_get_cancellable (task),
|
||||
sysprof_check_supported_ping_cb,
|
||||
g_object_ref (task));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_check_supported_async (GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_check_supported_async);
|
||||
|
||||
/* Get access to the System D-Bus and check to see if we can ping the
|
||||
* service that is found at org.gnome.Sysprof3.
|
||||
*/
|
||||
|
||||
g_bus_get (G_BUS_TYPE_SYSTEM,
|
||||
cancellable,
|
||||
sysprof_check_supported_bus_cb,
|
||||
g_steal_pointer (&task));
|
||||
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_check_supported_finish (GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_TASK (result), FALSE);
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
/* sysprof-check.h
|
||||
*
|
||||
* Copyright 2019 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 <gio/gio.h>
|
||||
|
||||
#include "sysprof-version-macros.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_check_supported_async (GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_check_supported_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,157 +0,0 @@
|
||||
/* sysprof-color-cycle.c
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-color-cycle"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
|
||||
G_DEFINE_BOXED_TYPE (SysprofColorCycle, sysprof_color_cycle, sysprof_color_cycle_ref, sysprof_color_cycle_unref)
|
||||
|
||||
static const gchar *default_colors[] = {
|
||||
|
||||
"#1a5fb4", /* Blue 5 */
|
||||
"#26a269", /* Green 5 */
|
||||
"#e5a50a", /* Yellow 5 */
|
||||
"#c64600", /* Orange 5 */
|
||||
"#a51d2d", /* Red 5 */
|
||||
"#613583", /* Purple 5 */
|
||||
"#63452c", /* Brown 5 */
|
||||
|
||||
"#1c71d8", /* Blue 4 */
|
||||
"#2ec27e", /* Green 4 */
|
||||
"#f5c211", /* Yellow 4 */
|
||||
"#e66100", /* Orange 4 */
|
||||
"#c01c28", /* Red 4 */
|
||||
"#813d9c", /* Purple 4 */
|
||||
"#865e3c", /* Brown 4 */
|
||||
|
||||
"#3584e4", /* Blue 3 */
|
||||
"#33d17a", /* Green 3 */
|
||||
"#f6d32d", /* Yellow 3 */
|
||||
"#ff7800", /* Orange 3 */
|
||||
"#e01b24", /* Red 3 */
|
||||
"#9141ac", /* Purple 3 */
|
||||
"#986a44", /* Brown 3 */
|
||||
|
||||
"#62a0ea", /* Blue 2 */
|
||||
"#57e389", /* Green 2 */
|
||||
"#f8e45c", /* Yellow 2 */
|
||||
"#ffa348", /* Orange 2 */
|
||||
"#ed333b", /* Red 2 */
|
||||
"#c061cb", /* Purple 2 */
|
||||
"#b5835a", /* Brown 2 */
|
||||
|
||||
"#99c1f1", /* Blue 1 */
|
||||
"#8ff0a4", /* Green 1 */
|
||||
"#f9f06b", /* Yellow 1 */
|
||||
"#ffbe6f", /* Orange 1 */
|
||||
"#f66151", /* Red 1 */
|
||||
"#dc8add", /* Purple 1 */
|
||||
"#cdab8f", /* Brown 1 */
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
struct _SysprofColorCycle
|
||||
{
|
||||
volatile gint ref_count;
|
||||
GdkRGBA *colors;
|
||||
gsize n_colors;
|
||||
guint position;
|
||||
};
|
||||
|
||||
static void
|
||||
sysprof_color_cycle_destroy (SysprofColorCycle *self)
|
||||
{
|
||||
g_free (self->colors);
|
||||
g_slice_free (SysprofColorCycle, self);
|
||||
}
|
||||
|
||||
SysprofColorCycle *
|
||||
sysprof_color_cycle_new (void)
|
||||
{
|
||||
SysprofColorCycle *self;
|
||||
|
||||
self = g_slice_new0 (SysprofColorCycle);
|
||||
self->ref_count = 1;
|
||||
self->n_colors = g_strv_length ((gchar **)default_colors);
|
||||
self->colors = g_new0 (GdkRGBA, self->n_colors);
|
||||
|
||||
for (guint i = 0; default_colors[i]; i++)
|
||||
{
|
||||
if G_UNLIKELY (!gdk_rgba_parse (&self->colors[i], default_colors[i]))
|
||||
g_warning ("Failed to parse color %s into an RGBA", default_colors[i]);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
SysprofColorCycle *
|
||||
sysprof_color_cycle_ref (SysprofColorCycle *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
g_return_val_if_fail (self->ref_count > 0, NULL);
|
||||
g_atomic_int_inc (&self->ref_count);
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_color_cycle_unref (SysprofColorCycle *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->ref_count > 0);
|
||||
if (g_atomic_int_dec_and_test (&self->ref_count))
|
||||
sysprof_color_cycle_destroy (self);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_color_cycle_next (SysprofColorCycle *self,
|
||||
GdkRGBA *rgba)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->position < self->n_colors);
|
||||
|
||||
*rgba = self->colors[self->position];
|
||||
|
||||
/*
|
||||
* TODO: Adjust color HSV/etc
|
||||
*
|
||||
* We could simply adjust the brightness/etc after we dispatch
|
||||
* a color so that we get darker as we go.
|
||||
*/
|
||||
|
||||
self->position = (self->position + 1) % self->n_colors;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_color_cycle_reset (SysprofColorCycle *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
for (guint i = 0; default_colors[i]; i++)
|
||||
{
|
||||
if G_UNLIKELY (!gdk_rgba_parse (&self->colors[i], default_colors[i]))
|
||||
g_warning ("Failed to parse color %s into an RGBA", default_colors[i]);
|
||||
}
|
||||
|
||||
self->position = 0;
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
/* sysprof-color-cycle.h
|
||||
*
|
||||
* Copyright 2016-2019 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>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_COLOR_CYCLE (sysprof_color_cycle_get_type())
|
||||
|
||||
typedef struct _SysprofColorCycle SysprofColorCycle;
|
||||
|
||||
GType sysprof_color_cycle_get_type (void);
|
||||
SysprofColorCycle *sysprof_color_cycle_ref (SysprofColorCycle *self);
|
||||
void sysprof_color_cycle_unref (SysprofColorCycle *self);
|
||||
SysprofColorCycle *sysprof_color_cycle_new (void);
|
||||
void sysprof_color_cycle_reset (SysprofColorCycle *self);
|
||||
void sysprof_color_cycle_next (SysprofColorCycle *self,
|
||||
GdkRGBA *rgba);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofColorCycle, sysprof_color_cycle_unref)
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,284 +0,0 @@
|
||||
/* sysprof-counters-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-counters-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-counters-aid.h"
|
||||
#include "sysprof-line-visualizer.h"
|
||||
#include "sysprof-marks-page.h"
|
||||
#include "sysprof-time-visualizer.h"
|
||||
|
||||
struct _SysprofCountersAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofCountersAid, sysprof_counters_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
static void
|
||||
on_group_activated_cb (SysprofVisualizerGroup *group,
|
||||
SysprofPage *page)
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
|
||||
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
|
||||
g_assert (SYSPROF_IS_PAGE (page));
|
||||
|
||||
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
|
||||
sysprof_display_set_visible_page (display, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_counters_aid_new:
|
||||
*
|
||||
* Create a new #SysprofCountersAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofCountersAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_counters_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_COUNTERS_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
}
|
||||
|
||||
static gchar *
|
||||
build_title (const SysprofCaptureCounter *ctr)
|
||||
{
|
||||
GString *str;
|
||||
|
||||
str = g_string_new (NULL);
|
||||
|
||||
if (ctr->category[0] != 0)
|
||||
{
|
||||
if (str->len)
|
||||
g_string_append_c (str, ' ');
|
||||
g_string_append (str, ctr->category);
|
||||
}
|
||||
|
||||
if (ctr->name[0] != 0)
|
||||
{
|
||||
if (str->len)
|
||||
g_string_append (str, " — ");
|
||||
g_string_append (str, ctr->name);
|
||||
}
|
||||
|
||||
if (ctr->description[0] != 0)
|
||||
{
|
||||
if (str->len)
|
||||
g_string_append_printf (str, " (%s)", ctr->description);
|
||||
else
|
||||
g_string_append (str, ctr->description);
|
||||
}
|
||||
|
||||
if (str->len == 0)
|
||||
/* this is untranslated on purpose */
|
||||
g_string_append_printf (str, "Counter %d", ctr->id);
|
||||
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_counters (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
GArray *counters = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (counters != NULL);
|
||||
|
||||
if (def->n_counters > 0)
|
||||
g_array_append_vals (counters, def->counters, def->n_counters);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_COUNTERS_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_counters, counters);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_COUNTERS_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_counters_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_counters_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_counters_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)) && counters->len > 0)
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *group;
|
||||
SysprofVisualizer *combined;
|
||||
GtkWidget *page;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"has-page", TRUE,
|
||||
"title", _("Counters"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
combined = g_object_new (SYSPROF_TYPE_TIME_VISUALIZER,
|
||||
"title", _("Counters"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (group, combined, -1, TRUE);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
g_autofree gchar *title = build_title (ctr);
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
rgba.alpha = .5;
|
||||
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_time_visualizer_add_counter (SYSPROF_TIME_VISUALIZER (combined), ctr->id, &rgba);
|
||||
sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), -1, TRUE);
|
||||
}
|
||||
|
||||
sysprof_display_add_group (present->display, group);
|
||||
|
||||
page = sysprof_marks_page_new (sysprof_display_get_zoom_manager (present->display),
|
||||
SYSPROF_MARKS_MODEL_COUNTERS);
|
||||
gtk_widget_show (page);
|
||||
|
||||
g_signal_connect_object (group,
|
||||
"group-activated",
|
||||
G_CALLBACK (on_group_activated_cb),
|
||||
page,
|
||||
0);
|
||||
sysprof_display_add_page (present->display, SYSPROF_PAGE (page));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_class_init (SysprofCountersAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_counters_aid_prepare;
|
||||
aid_class->present_async = sysprof_counters_aid_present_async;
|
||||
aid_class->present_finish = sysprof_counters_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_init (SysprofCountersAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Counters"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
|
||||
}
|
||||
@ -1,357 +0,0 @@
|
||||
/* sysprof-cpu-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-cpu-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-cpu-aid.h"
|
||||
#include "sysprof-line-visualizer.h"
|
||||
#include "sysprof-procs-visualizer.h"
|
||||
|
||||
struct _SysprofCpuAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
GArray *counters;
|
||||
guint has_processes : 1;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofCpuAid, sysprof_cpu_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_pointer (&p->counters, g_array_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_cpu_aid_new:
|
||||
*
|
||||
* Create a new #SysprofCpuAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofCpuAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_cpu_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CPU_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
#ifdef __linux__
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_CPU_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_hostinfo_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_info (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
Present *p = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (p != NULL);
|
||||
g_assert (p->counters != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
|
||||
{
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *counter = &def->counters[i];
|
||||
|
||||
if (g_strcmp0 (counter->category, "CPU Percent") == 0 ||
|
||||
g_strcmp0 (counter->category, "CPU Frequency") == 0)
|
||||
g_array_append_vals (p->counters, counter, 1);
|
||||
}
|
||||
}
|
||||
else if (!p->has_processes &&
|
||||
(frame->type == SYSPROF_CAPTURE_FRAME_PROCESS ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_EXIT))
|
||||
{
|
||||
p->has_processes = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_CPU_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_info, present);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&present->counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = {
|
||||
SYSPROF_CAPTURE_FRAME_CTRDEF,
|
||||
SYSPROF_CAPTURE_FRAME_PROCESS,
|
||||
SYSPROF_CAPTURE_FRAME_EXIT,
|
||||
};
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_CPU_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
present.counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
present.has_processes = FALSE;
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_cpu_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_cpu_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_cpu_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
g_autoptr(SysprofColorCycle) freq_cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *usage;
|
||||
SysprofVisualizerGroup *freq;
|
||||
SysprofVisualizer *freq_row = NULL;
|
||||
SysprofVisualizer *over_row = NULL;
|
||||
gboolean found_combined = FALSE;
|
||||
gboolean has_usage = FALSE;
|
||||
gboolean has_freq = FALSE;
|
||||
|
||||
usage = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"priority", -1000,
|
||||
"title", _("CPU Usage"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
freq = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"priority", -999,
|
||||
"title", _("CPU Frequency"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
freq_row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", _("CPU Frequency (All)"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (freq, freq_row, -1, FALSE);
|
||||
|
||||
over_row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", _("CPU Usage (All)"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_strcmp0 (ctr->category, "CPU Percent") == 0)
|
||||
{
|
||||
if (strstr (ctr->name, "Combined") != NULL)
|
||||
{
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
found_combined = TRUE;
|
||||
|
||||
gdk_rgba_parse (&rgba, "#1a5fb4");
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
/* Translators: CPU is the processor. */
|
||||
"title", _("CPU Usage (All)"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
rgba.alpha = 0.5;
|
||||
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), 0, FALSE);
|
||||
has_usage = TRUE;
|
||||
}
|
||||
else if (g_str_has_prefix (ctr->name, "Total CPU "))
|
||||
{
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", ctr->name,
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (over_row), ctr->id, &rgba);
|
||||
rgba.alpha = 0.5;
|
||||
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), -1, TRUE);
|
||||
has_usage = TRUE;
|
||||
}
|
||||
}
|
||||
else if (g_strcmp0 (ctr->category, "CPU Frequency") == 0)
|
||||
{
|
||||
if (g_str_has_prefix (ctr->name, "CPU "))
|
||||
{
|
||||
g_autofree gchar *title = g_strdup_printf ("%s Frequency", ctr->name);
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
sysprof_color_cycle_next (freq_cycle, &rgba);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (freq_row), ctr->id, &rgba);
|
||||
sysprof_line_visualizer_set_dash (SYSPROF_LINE_VISUALIZER (freq_row), ctr->id, TRUE);
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_line_visualizer_set_dash (SYSPROF_LINE_VISUALIZER (row), ctr->id, TRUE);
|
||||
sysprof_visualizer_group_insert (freq, SYSPROF_VISUALIZER (row), -1, TRUE);
|
||||
|
||||
has_freq = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (present->has_processes)
|
||||
{
|
||||
GtkWidget *row;
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_PROCS_VISUALIZER,
|
||||
"title", _("Processes"),
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), -1, TRUE);
|
||||
}
|
||||
|
||||
if (has_usage && !found_combined)
|
||||
sysprof_visualizer_group_insert (usage, over_row, 0, FALSE);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (over_row));
|
||||
|
||||
if (has_usage)
|
||||
sysprof_display_add_group (present->display, usage);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (usage));
|
||||
|
||||
if (has_freq)
|
||||
sysprof_display_add_group (present->display, freq);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (freq));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_class_init (SysprofCpuAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_cpu_aid_prepare;
|
||||
aid_class->present_async = sysprof_cpu_aid_present_async;
|
||||
aid_class->present_finish = sysprof_cpu_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_init (SysprofCpuAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("CPU Usage"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
|
||||
}
|
||||
@ -1,453 +0,0 @@
|
||||
/* sysprof-depth-visualizer.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-depth-visualizer"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "pointcache.h"
|
||||
#include "sysprof-depth-visualizer.h"
|
||||
|
||||
struct _SysprofDepthVisualizer
|
||||
{
|
||||
SysprofVisualizer parent_instance;
|
||||
SysprofCaptureReader *reader;
|
||||
PointCache *points;
|
||||
guint reload_source;
|
||||
guint mode;
|
||||
int last_width;
|
||||
int last_height;
|
||||
guint reloading : 1;
|
||||
guint needs_reload : 1;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureReader *reader;
|
||||
PointCache *pc;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
gint64 duration;
|
||||
guint max_n_addrs;
|
||||
guint mode;
|
||||
} State;
|
||||
|
||||
static void sysprof_depth_visualizer_reload (SysprofDepthVisualizer *self);
|
||||
|
||||
G_DEFINE_TYPE (SysprofDepthVisualizer, sysprof_depth_visualizer, SYSPROF_TYPE_VISUALIZER)
|
||||
|
||||
static void
|
||||
state_free (State *st)
|
||||
{
|
||||
g_clear_pointer (&st->reader, sysprof_capture_reader_unref);
|
||||
g_clear_pointer (&st->pc, point_cache_unref);
|
||||
g_slice_free (State, st);
|
||||
}
|
||||
|
||||
static bool
|
||||
discover_max_n_addr (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
|
||||
State *st = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
|
||||
g_assert (st != NULL);
|
||||
|
||||
st->max_n_addrs = MAX (st->max_n_addrs, sample->n_addrs);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
build_point_cache_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
|
||||
State *st = user_data;
|
||||
gdouble x, y;
|
||||
gboolean has_kernel = FALSE;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
|
||||
g_assert (st != NULL);
|
||||
|
||||
x = (frame->time - st->begin_time) / (gdouble)st->duration;
|
||||
y = sample->n_addrs / (gdouble)st->max_n_addrs;
|
||||
|
||||
/* If this contains a context-switch (meaning we're going into the kernel
|
||||
* to do some work, use a negative value for Y so that we know later on
|
||||
* that we should draw it with a different color (after removing the negation
|
||||
* on the value.
|
||||
*
|
||||
* We skip past the first index, which is always a context switch as it is
|
||||
* our perf handler.
|
||||
*/
|
||||
for (guint i = 1; i < sample->n_addrs; i++)
|
||||
{
|
||||
SysprofAddressContext kind;
|
||||
|
||||
if (sysprof_address_is_context_switch (sample->addrs[i], &kind))
|
||||
{
|
||||
has_kernel = TRUE;
|
||||
y = -y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_kernel)
|
||||
point_cache_add_point_to_set (st->pc, 1, x, y);
|
||||
else
|
||||
point_cache_add_point_to_set (st->pc, 2, x, y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE, };
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
SysprofCaptureCondition *condition;
|
||||
State *st = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (source_object));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
if (st->duration != 0)
|
||||
{
|
||||
cursor = sysprof_capture_cursor_new (st->reader);
|
||||
condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, discover_max_n_addr, st);
|
||||
sysprof_capture_cursor_reset (cursor);
|
||||
sysprof_capture_cursor_foreach (cursor, build_point_cache_cb, st);
|
||||
}
|
||||
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&st->pc),
|
||||
(GDestroyNotify) point_cache_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
apply_point_cache_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)object;
|
||||
PointCache *pc;
|
||||
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
self->reloading = FALSE;
|
||||
|
||||
if ((pc = g_task_propagate_pointer (G_TASK (result), NULL)))
|
||||
{
|
||||
g_clear_pointer (&self->points, point_cache_unref);
|
||||
self->points = g_steal_pointer (&pc);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
if (self->needs_reload)
|
||||
sysprof_depth_visualizer_reload (self);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_reload (SysprofDepthVisualizer *self)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
GtkAllocation alloc;
|
||||
State *st;
|
||||
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
|
||||
self->needs_reload = TRUE;
|
||||
|
||||
if (self->reloading)
|
||||
return;
|
||||
|
||||
self->reloading = TRUE;
|
||||
self->needs_reload = FALSE;
|
||||
|
||||
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
|
||||
|
||||
st = g_slice_new0 (State);
|
||||
st->reader = sysprof_capture_reader_ref (self->reader);
|
||||
st->pc = point_cache_new ();
|
||||
st->max_n_addrs = 0;
|
||||
st->begin_time = sysprof_capture_reader_get_start_time (self->reader);
|
||||
st->end_time = sysprof_capture_reader_get_end_time (self->reader);
|
||||
st->duration = st->end_time - st->begin_time;
|
||||
st->mode = self->mode;
|
||||
|
||||
point_cache_add_set (st->pc, 1);
|
||||
point_cache_add_set (st->pc, 2);
|
||||
|
||||
task = g_task_new (self, NULL, apply_point_cache_cb, NULL);
|
||||
g_task_set_source_tag (task, sysprof_depth_visualizer_reload);
|
||||
g_task_set_task_data (task, st, (GDestroyNotify) state_free);
|
||||
g_task_run_in_thread (task, sysprof_depth_visualizer_worker);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_set_reader (SysprofVisualizer *row,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)row;
|
||||
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
|
||||
if (self->reader != reader)
|
||||
{
|
||||
if (self->reader != NULL)
|
||||
{
|
||||
sysprof_capture_reader_unref (self->reader);
|
||||
self->reader = NULL;
|
||||
}
|
||||
|
||||
if (reader != NULL)
|
||||
{
|
||||
self->reader = sysprof_capture_reader_ref (reader);
|
||||
sysprof_depth_visualizer_reload (self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)widget;
|
||||
GtkAllocation alloc;
|
||||
GdkRectangle clip;
|
||||
const Point *points;
|
||||
cairo_t *cr;
|
||||
guint n_points = 0;
|
||||
GdkRGBA user;
|
||||
GdkRGBA system;
|
||||
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
g_assert (snapshot != NULL);
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_depth_visualizer_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
if (self->points == NULL)
|
||||
return;
|
||||
|
||||
gdk_rgba_parse (&user, "#1a5fb4");
|
||||
gdk_rgba_parse (&system, "#3584e4");
|
||||
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
|
||||
|
||||
/* FIXME: we should abstract visualizer drawing into regions so that we
|
||||
* can still know the region we're drawing.
|
||||
*/
|
||||
#if 0
|
||||
if (!gdk_cairo_get_clip_rectangle (cr, &clip))
|
||||
return;
|
||||
#else
|
||||
clip.x = alloc.x = 0;
|
||||
clip.y = alloc.y = 0;
|
||||
clip.width = alloc.width;
|
||||
clip.height = alloc.height;
|
||||
#endif
|
||||
|
||||
/* Draw user-space stacks */
|
||||
if (self->mode != SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY &&
|
||||
(points = point_cache_get_points (self->points, 1, &n_points)))
|
||||
{
|
||||
g_autofree SysprofVisualizerAbsolutePoint *out_points = NULL;
|
||||
|
||||
out_points = g_new (SysprofVisualizerAbsolutePoint, n_points);
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (widget),
|
||||
(const SysprofVisualizerRelativePoint *)points,
|
||||
n_points, out_points, n_points);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
gdk_cairo_set_source_rgba (cr, &user);
|
||||
|
||||
for (guint i = 0; i < n_points; i++)
|
||||
{
|
||||
gdouble x, y;
|
||||
|
||||
x = out_points[i].x;
|
||||
y = out_points[i].y;
|
||||
|
||||
if (x < clip.x)
|
||||
continue;
|
||||
|
||||
if (x > clip.x + clip.width)
|
||||
break;
|
||||
|
||||
for (guint j = i + 1; j < n_points; j++)
|
||||
{
|
||||
if (out_points[j].x != x)
|
||||
break;
|
||||
|
||||
y = MIN (y, out_points[j].y);
|
||||
}
|
||||
|
||||
x += alloc.x;
|
||||
|
||||
cairo_move_to (cr, (guint)x + .5, alloc.height);
|
||||
cairo_line_to (cr, (guint)x + .5, y);
|
||||
}
|
||||
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
/* Draw kernel-space stacks */
|
||||
if (self->mode != SYSPROF_DEPTH_VISUALIZER_USER_ONLY &&
|
||||
(points = point_cache_get_points (self->points, 2, &n_points)))
|
||||
{
|
||||
g_autofree SysprofVisualizerAbsolutePoint *out_points = NULL;
|
||||
|
||||
out_points = g_new (SysprofVisualizerAbsolutePoint, n_points);
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (widget),
|
||||
(const SysprofVisualizerRelativePoint *)points,
|
||||
n_points, out_points, n_points);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
gdk_cairo_set_source_rgba (cr, &system);
|
||||
|
||||
for (guint i = 0; i < n_points; i++)
|
||||
{
|
||||
gdouble x, y;
|
||||
|
||||
x = out_points[i].x;
|
||||
y = out_points[i].y;
|
||||
|
||||
if (x < clip.x)
|
||||
continue;
|
||||
|
||||
if (x > clip.x + clip.width)
|
||||
break;
|
||||
|
||||
for (guint j = i + 1; j < n_points; j++)
|
||||
{
|
||||
if (out_points[j].x != x)
|
||||
break;
|
||||
|
||||
y = MIN (y, out_points[j].y);
|
||||
}
|
||||
|
||||
x += alloc.x;
|
||||
|
||||
cairo_move_to (cr, (guint)x + .5, alloc.height);
|
||||
cairo_line_to (cr, (guint)x + .5, y);
|
||||
}
|
||||
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_depth_visualizer_do_reload (gpointer data)
|
||||
{
|
||||
SysprofDepthVisualizer *self = data;
|
||||
self->reload_source = 0;
|
||||
sysprof_depth_visualizer_reload (self);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_queue_reload (SysprofDepthVisualizer *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
|
||||
g_clear_handle_id (&self->reload_source, g_source_remove);
|
||||
self->reload_source = g_idle_add (sysprof_depth_visualizer_do_reload, self);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)widget;
|
||||
|
||||
if (width != self->last_width || height != self->last_height)
|
||||
{
|
||||
sysprof_depth_visualizer_queue_reload (SYSPROF_DEPTH_VISUALIZER (widget));
|
||||
self->last_width = width;
|
||||
self->last_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)object;
|
||||
|
||||
g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
|
||||
g_clear_handle_id (&self->reload_source, g_source_remove);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_depth_visualizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_class_init (SysprofDepthVisualizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofVisualizerClass *row_class = SYSPROF_VISUALIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_depth_visualizer_finalize;
|
||||
|
||||
widget_class->snapshot = sysprof_depth_visualizer_snapshot;
|
||||
widget_class->size_allocate = sysprof_depth_visualizer_size_allocate;
|
||||
|
||||
row_class->set_reader = sysprof_depth_visualizer_set_reader;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_init (SysprofDepthVisualizer *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofVisualizer *
|
||||
sysprof_depth_visualizer_new (SysprofDepthVisualizerMode mode)
|
||||
{
|
||||
SysprofDepthVisualizer *self;
|
||||
|
||||
g_return_val_if_fail (mode == SYSPROF_DEPTH_VISUALIZER_COMBINED ||
|
||||
mode == SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY ||
|
||||
mode == SYSPROF_DEPTH_VISUALIZER_USER_ONLY,
|
||||
NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DEPTH_VISUALIZER, NULL);
|
||||
self->mode = mode;
|
||||
|
||||
return SYSPROF_VISUALIZER (g_steal_pointer (&self));
|
||||
}
|
||||
@ -1,325 +0,0 @@
|
||||
/* sysprof-details-page.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-details-page"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-mark-detail.h"
|
||||
#include "sysprof-details-page.h"
|
||||
#include "sysprof-ui-private.h"
|
||||
|
||||
struct _SysprofDetailsPage
|
||||
{
|
||||
GtkWidget parent_instance ;
|
||||
|
||||
/* Template Objects */
|
||||
|
||||
GListStore *marks_store;
|
||||
GtkSortListModel *mark_sort_model;
|
||||
GtkLabel *counters;
|
||||
GtkLabel *duration;
|
||||
GtkLabel *filename;
|
||||
GtkLabel *allocations;
|
||||
GtkLabel *forks;
|
||||
GtkLabel *marks;
|
||||
GtkLabel *processes;
|
||||
GtkLabel *samples;
|
||||
GtkLabel *start_time;
|
||||
GtkLabel *cpu_label;
|
||||
|
||||
guint next_row;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofDetailsPage, sysprof_details_page, GTK_TYPE_WIDGET)
|
||||
|
||||
#if GLIB_CHECK_VERSION(2, 56, 0)
|
||||
# define _g_date_time_new_from_iso8601 g_date_time_new_from_iso8601
|
||||
#else
|
||||
static GDateTime *
|
||||
_g_date_time_new_from_iso8601 (const gchar *str,
|
||||
GTimeZone *default_tz)
|
||||
{
|
||||
GTimeVal tv;
|
||||
|
||||
if (g_time_val_from_iso8601 (str, &tv))
|
||||
{
|
||||
g_autoptr(GDateTime) dt = g_date_time_new_from_timeval_utc (&tv);
|
||||
|
||||
if (default_tz)
|
||||
return g_date_time_to_timezone (dt, default_tz);
|
||||
else
|
||||
return g_steal_pointer (&dt);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
format_time (GObject *unused,
|
||||
gint64 time)
|
||||
{
|
||||
return time ? _sysprof_format_duration (time) : g_strdup("—");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_dispose (GObject *object)
|
||||
{
|
||||
SysprofDetailsPage *self = (SysprofDetailsPage *)object;
|
||||
GtkWidget *child;
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_details_page_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_class_init (SysprofDetailsPageClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_details_page_dispose;
|
||||
|
||||
g_type_ensure (SYSPROF_TYPE_MARK_DETAIL);
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-details-page.ui");
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, allocations);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, counters);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, cpu_label);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, duration);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, filename);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, forks);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks_store);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, mark_sort_model);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, processes);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, samples);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, start_time);
|
||||
gtk_widget_class_bind_template_callback (widget_class, format_time);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_init (SysprofDetailsPage *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->next_row = 8;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
sysprof_details_page_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_DETAILS_PAGE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
update_cpu_info_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(SysprofDetailsPage) self = user_data;
|
||||
g_autofree gchar *str = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
if ((str = g_task_propagate_pointer (G_TASK (result), NULL)))
|
||||
gtk_label_set_label (self->cpu_label, str);
|
||||
}
|
||||
|
||||
static bool
|
||||
cpu_info_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
const SysprofCaptureFileChunk *fc = (gpointer)frame;
|
||||
const gchar *endptr;
|
||||
const gchar *line;
|
||||
gchar **str = user_data;
|
||||
|
||||
line = memmem ((gchar *)fc->data, fc->len, "model name", 10);
|
||||
|
||||
if (!line)
|
||||
return FALSE;
|
||||
|
||||
endptr = (gchar *)fc->data + fc->len;
|
||||
endptr = memchr (line, '\n', endptr - line);
|
||||
|
||||
if (endptr)
|
||||
{
|
||||
gchar *tmp = *str = g_strndup (line, endptr - line);
|
||||
for (; *tmp && *tmp != ':'; tmp++)
|
||||
*tmp = ' ';
|
||||
if (*tmp == ':')
|
||||
*tmp = ' ';
|
||||
g_strstrip (*str);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_update_cpu_info_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofCaptureCursor *cursor = task_data;
|
||||
gchar *str = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (cursor != NULL);
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, cpu_info_cb, &str);
|
||||
g_task_return_pointer (task, g_steal_pointer (&str), g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_update_cpu_info (SysprofDetailsPage *self,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
g_assert (reader != NULL);
|
||||
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor,
|
||||
sysprof_capture_condition_new_where_file ("/proc/cpuinfo"));
|
||||
|
||||
task = g_task_new (NULL, NULL, update_cpu_info_cb, g_object_ref (self));
|
||||
g_task_set_task_data (task,
|
||||
g_steal_pointer (&cursor),
|
||||
(GDestroyNotify) sysprof_capture_cursor_unref);
|
||||
g_task_run_in_thread (task, sysprof_details_page_update_cpu_info_worker);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_details_page_set_reader (SysprofDetailsPage *self,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
g_autoptr(GDateTime) dt = NULL;
|
||||
g_autoptr(GDateTime) local = NULL;
|
||||
g_autofree gchar *duration_str = NULL;
|
||||
const gchar *filename;
|
||||
const gchar *capture_at;
|
||||
SysprofCaptureStat st_buf;
|
||||
gint64 duration;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
g_return_if_fail (reader != NULL);
|
||||
|
||||
sysprof_details_page_update_cpu_info (self, reader);
|
||||
|
||||
if (!(filename = sysprof_capture_reader_get_filename (reader)))
|
||||
filename = _("Memory Capture");
|
||||
|
||||
gtk_label_set_label (self->filename, filename);
|
||||
|
||||
if ((capture_at = sysprof_capture_reader_get_time (reader)) &&
|
||||
(dt = _g_date_time_new_from_iso8601 (capture_at, NULL)) &&
|
||||
(local = g_date_time_to_local (dt)))
|
||||
{
|
||||
g_autofree gchar *str = g_date_time_format (local, "%x %X");
|
||||
gtk_label_set_label (self->start_time, str);
|
||||
}
|
||||
|
||||
duration = sysprof_capture_reader_get_end_time (reader) -
|
||||
sysprof_capture_reader_get_start_time (reader);
|
||||
duration_str = g_strdup_printf (_("%0.4lf seconds"), duration / (gdouble)SYSPROF_NSEC_PER_SEC);
|
||||
gtk_label_set_label (self->duration, duration_str);
|
||||
|
||||
if (sysprof_capture_reader_get_stat (reader, &st_buf))
|
||||
{
|
||||
#define SET_FRAME_COUNT(field, TYPE) \
|
||||
G_STMT_START { \
|
||||
g_autofree gchar *str = NULL; \
|
||||
str = g_strdup_printf ("%"G_GSIZE_FORMAT, st_buf.frame_count[TYPE]); \
|
||||
gtk_label_set_label (self->field, str); \
|
||||
} G_STMT_END
|
||||
|
||||
SET_FRAME_COUNT (samples, SYSPROF_CAPTURE_FRAME_SAMPLE);
|
||||
SET_FRAME_COUNT (marks, SYSPROF_CAPTURE_FRAME_MARK);
|
||||
SET_FRAME_COUNT (processes, SYSPROF_CAPTURE_FRAME_PROCESS);
|
||||
SET_FRAME_COUNT (forks, SYSPROF_CAPTURE_FRAME_FORK);
|
||||
SET_FRAME_COUNT (counters, SYSPROF_CAPTURE_FRAME_CTRSET);
|
||||
SET_FRAME_COUNT (allocations, SYSPROF_CAPTURE_FRAME_ALLOCATION);
|
||||
|
||||
#undef SET_FRAME_COUNT
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_details_page_add_mark (SysprofDetailsPage *self,
|
||||
const gchar *mark,
|
||||
gint64 min,
|
||||
gint64 max,
|
||||
gint64 avg,
|
||||
gint64 hits)
|
||||
{
|
||||
SysprofMarkDetail *detail;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
|
||||
detail = sysprof_mark_detail_new (mark, min, max, avg, hits);
|
||||
|
||||
g_list_store_append (self->marks_store, detail);
|
||||
/*gtk_list_store_append (self->marks_store, &iter);
|
||||
gtk_list_store_set (self->marks_store, &iter,
|
||||
0, mark,
|
||||
1, min ? _sysprof_format_duration (min) : "—",
|
||||
2, max ? _sysprof_format_duration (max) : "—",
|
||||
3, avg ? _sysprof_format_duration (avg) : "—",
|
||||
4, hits,
|
||||
5, detail,
|
||||
-1);*/
|
||||
g_object_unref (detail);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_details_page_add_marks (SysprofDetailsPage *self,
|
||||
const SysprofMarkStat *marks,
|
||||
guint n_marks)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
g_return_if_fail (marks != NULL || n_marks == 0);
|
||||
|
||||
if (marks == NULL || n_marks == 0)
|
||||
return;
|
||||
|
||||
/* Be reasonable */
|
||||
if (n_marks > 100)
|
||||
n_marks = 100;
|
||||
|
||||
for (guint i = 0; i < n_marks; i++)
|
||||
sysprof_details_page_add_mark (self,
|
||||
marks[i].name,
|
||||
marks[i].min,
|
||||
marks[i].max,
|
||||
marks[i].avg,
|
||||
marks[i].count);
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/* sysprof-details-page.h
|
||||
*
|
||||
* Copyright 2019 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 <sysprof-capture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SYSPROF_ALIGNED_BEGIN (8)
|
||||
typedef struct
|
||||
{
|
||||
gchar name[152];
|
||||
guint64 count;
|
||||
gint64 max;
|
||||
gint64 min;
|
||||
gint64 avg;
|
||||
guint64 avg_count;
|
||||
} SysprofMarkStat
|
||||
SYSPROF_ALIGNED_END (8);
|
||||
|
||||
#define SYSPROF_TYPE_DETAILS_PAGE (sysprof_details_page_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDetailsPage, sysprof_details_page, SYSPROF, DETAILS_PAGE, GtkWidget)
|
||||
|
||||
GtkWidget *sysprof_details_page_new (void);
|
||||
void sysprof_details_page_set_reader (SysprofDetailsPage *self,
|
||||
SysprofCaptureReader *reader);
|
||||
void sysprof_details_page_add_marks (SysprofDetailsPage *self,
|
||||
const SysprofMarkStat *marks,
|
||||
guint n_marks);
|
||||
void sysprof_details_page_add_mark (SysprofDetailsPage *self,
|
||||
const gchar *mark,
|
||||
gint64 min,
|
||||
gint64 max,
|
||||
gint64 avg,
|
||||
gint64 hits);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,361 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SysprofDetailsPage" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="AdwPreferencesPage">
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Capture</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Location</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="filename">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Recorded At</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="start_time">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Duration</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="duration">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">CPU Model</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="cpu_label">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Statistics</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Stack Traces</property>
|
||||
<property name="subtitle" translatable="yes">Number of stack traces sampled for performance callgraphs</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="samples">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Marks</property>
|
||||
<property name="subtitle" translatable="yes">Number of marks seen</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="marks">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Processes</property>
|
||||
<property name="subtitle" translatable="yes">Number of processes seen</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="processes">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Forks</property>
|
||||
<property name="subtitle" translatable="yes">Number of times a process forked</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="forks">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Memory Allocations</property>
|
||||
<property name="subtitle" translatable="yes">Number of stack traces recorded for tracing memory allocations</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="allocations">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Counters</property>
|
||||
<property name="subtitle" translatable="yes">Number of recorded counter values</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="counters">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Statistics</property>
|
||||
<child>
|
||||
<object class="GtkColumnView" id="marks_view">
|
||||
<property name="width-request">500</property>
|
||||
<property name="height-request">100</property>
|
||||
<property name="model">
|
||||
<object class="GtkNoSelection">
|
||||
<property name="model">mark_sort_model</property>
|
||||
</object>
|
||||
</property>
|
||||
<style>
|
||||
<class name="data-table"/>
|
||||
<class name="card"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Mark</property>
|
||||
<property name="expand">true</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkStringSorter">
|
||||
<property name="expression">
|
||||
<lookup name="label" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<binding name="label">
|
||||
<lookup name="label" type="SysprofMarkDetail">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Hits</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<lookup name="hits" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<lookup name="hits" type="SysprofMarkDetail">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Min</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<lookup name="min" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="format_time">
|
||||
<lookup name='min' type='SysprofMarkDetail'><lookup name='item'>GtkListItem</lookup></lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Max</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<lookup name="max" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="format_time">
|
||||
<lookup name='max' type='SysprofMarkDetail'><lookup name='item'>GtkListItem</lookup></lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Avg</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<lookup name="average" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="format_time">
|
||||
<lookup name='average' type='SysprofMarkDetail'><lookup name='item'>GtkListItem</lookup></lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<object class="GtkSortListModel" id="mark_sort_model">
|
||||
<property name="model">marks_store</property>
|
||||
<property name="incremental">true</property>
|
||||
<binding name="sorter">
|
||||
<lookup name="sorter">marks_view</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
<object class="GListStore" id="marks_store">
|
||||
</object>
|
||||
</interface>
|
||||
@ -1,269 +0,0 @@
|
||||
/* sysprof-diskstat-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-diskstat-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-duplex-visualizer.h"
|
||||
#include "sysprof-diskstat-aid.h"
|
||||
|
||||
struct _SysprofDiskstatAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofDiskstatAid, sysprof_diskstat_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_diskstat_aid_new:
|
||||
*
|
||||
* Create a new #SysprofDiskstatAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofDiskstatAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_diskstat_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_DISKSTAT_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DISKSTAT_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_diskstat_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_diskstat_counters (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
GArray *counters = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (counters != NULL);
|
||||
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *counter = &def->counters[i];
|
||||
|
||||
if (strcmp (counter->category, "Disk") == 0 &&
|
||||
(g_str_has_prefix (counter->name, "Total Reads") ||
|
||||
g_str_has_prefix (counter->name, "Total Writes")))
|
||||
g_array_append_vals (counters, counter, 1);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_DISKSTAT_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_diskstat_counters, counters);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static guint
|
||||
find_other_id (GArray *counters,
|
||||
const gchar *name)
|
||||
{
|
||||
g_autofree gchar *other = NULL;
|
||||
|
||||
g_assert (counters);
|
||||
g_assert (name != NULL);
|
||||
g_assert (g_str_has_prefix (name, "Total Reads"));
|
||||
|
||||
other = g_strdup_printf ("Total Writes%s", name + strlen ("Total Reads"));
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *c = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_str_equal (c->name, other))
|
||||
return c->id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_DISKSTAT_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_diskstat_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_diskstat_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_diskstat_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *group;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"title", _("Disk"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_str_has_prefix (ctr->name, "Total Reads"))
|
||||
{
|
||||
g_autofree gchar *title = NULL;
|
||||
gboolean is_combined;
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
guint other_id;
|
||||
|
||||
if (!(other_id = find_other_id (counters, ctr->name)))
|
||||
continue;
|
||||
|
||||
is_combined = g_str_equal (ctr->description, "Combined");
|
||||
|
||||
if (is_combined)
|
||||
title = g_strdup ("Disk Reads/Writes (All)");
|
||||
else
|
||||
title = g_strdup_printf ("Disk Reads/Writes%s", ctr->name + strlen ("Total Reads"));
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_DUPLEX_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", is_combined,
|
||||
NULL);
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
sysprof_duplex_visualizer_set_counters (SYSPROF_DUPLEX_VISUALIZER (row), ctr->id, other_id);
|
||||
sysprof_duplex_visualizer_set_colors (SYSPROF_DUPLEX_VISUALIZER (row), &rgba, &rgba);
|
||||
sysprof_duplex_visualizer_set_labels (SYSPROF_DUPLEX_VISUALIZER (row), _("Reads"), _("Writes"));
|
||||
sysprof_duplex_visualizer_set_use_diff (SYSPROF_DUPLEX_VISUALIZER (row), FALSE);
|
||||
sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), is_combined ? 0 : -1, !is_combined);
|
||||
}
|
||||
}
|
||||
|
||||
if (counters->len > 0)
|
||||
sysprof_display_add_group (present->display, group);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (group));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_class_init (SysprofDiskstatAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_diskstat_aid_prepare;
|
||||
aid_class->present_async = sysprof_diskstat_aid_present_async;
|
||||
aid_class->present_finish = sysprof_diskstat_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_init (SysprofDiskstatAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Disk"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "drive-harddisk-system-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-diskstat-aid.h
|
||||
*
|
||||
* Copyright 2019 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 "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DISKSTAT_AID (sysprof_diskstat_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDiskstatAid, sysprof_diskstat_aid, SYSPROF, DISKSTAT_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_diskstat_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,96 +0,0 @@
|
||||
/* sysprof-display.h
|
||||
*
|
||||
* Copyright 2019 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 <sysprof.h>
|
||||
|
||||
#include "sysprof-page.h"
|
||||
#include "sysprof-visualizer-group.h"
|
||||
#include "sysprof-zoom-manager.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DISPLAY (sysprof_display_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofDisplay, sysprof_display, SYSPROF, DISPLAY, GtkWidget)
|
||||
|
||||
struct _SysprofDisplayClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GtkWidget *sysprof_display_new (void);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GtkWidget *sysprof_display_new_for_profiler (SysprofProfiler *profiler);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
char *sysprof_display_dup_title (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofProfiler *sysprof_display_get_profiler (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_add_group (SysprofDisplay *self,
|
||||
SysprofVisualizerGroup *group);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_add_page (SysprofDisplay *self,
|
||||
SysprofPage *page);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofPage *sysprof_display_get_visible_page (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_set_visible_page (SysprofDisplay *self,
|
||||
SysprofPage *page);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofZoomManager *sysprof_display_get_zoom_manager (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_load_async (SysprofDisplay *self,
|
||||
SysprofCaptureReader *reader,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_display_load_finish (SysprofDisplay *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_display_is_empty (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_open (SysprofDisplay *self,
|
||||
GFile *file);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_save (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_display_get_can_save (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_stop_recording (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_display_get_can_replay (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDisplay *sysprof_display_replay (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_3_38
|
||||
void sysprof_display_add_to_selection (SysprofDisplay *self,
|
||||
gint64 begin_time,
|
||||
gint64 end_time);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="SysprofDisplay" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="hhomogeneous">0</property>
|
||||
<property name="vhomogeneous">0</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">assistant</property>
|
||||
<property name="child">
|
||||
<object class="SysprofProfilerAssistant" id="assistant">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">view</property>
|
||||
<property name="child">
|
||||
<object class="EggPaned">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="SysprofVisualizersFrame" id="visualizers">
|
||||
<property name="vexpand">false</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="pages">
|
||||
<property name="hhomogeneous">0</property>
|
||||
<property name="vhomogeneous">0</property>
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="title" translatable="yes">Details</property>
|
||||
<property name="name">details</property>
|
||||
<property name="child">
|
||||
<object class="SysprofDetailsPage" id="details">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">record</property>
|
||||
<property name="child">
|
||||
<object class="SysprofRecordingStateView" id="recording_view">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">failed</property>
|
||||
<property name="child">
|
||||
<object class="SysprofFailedStateView" id="failed_view">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,633 +0,0 @@
|
||||
/* sysprof-duplex-visualizer.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-duplex-visualizer"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pointcache.h"
|
||||
#include "sysprof-duplex-visualizer.h"
|
||||
|
||||
#define LABEL_HEIGHT_PX 10
|
||||
|
||||
struct _SysprofDuplexVisualizer
|
||||
{
|
||||
SysprofVisualizer parent_instance;
|
||||
|
||||
gint64 begin_time;
|
||||
gint64 duration;
|
||||
|
||||
guint rx_counter;
|
||||
guint tx_counter;
|
||||
|
||||
GdkRGBA rx_rgba;
|
||||
GdkRGBA tx_rgba;
|
||||
|
||||
gchar *rx_label;
|
||||
gchar *tx_label;
|
||||
|
||||
PointCache *cache;
|
||||
|
||||
guint rx_rgba_set : 1;
|
||||
guint tx_rgba_set : 1;
|
||||
guint use_diff : 1;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PointCache *cache;
|
||||
|
||||
gint64 begin_time;
|
||||
gint64 duration;
|
||||
|
||||
gint64 max_change;
|
||||
|
||||
/* Last value to convert to rate of change */
|
||||
gint64 last_rx_val;
|
||||
gint64 last_tx_val;
|
||||
|
||||
/* Counter IDs */
|
||||
guint rx;
|
||||
guint tx;
|
||||
|
||||
/* Do we need to subtract previous value */
|
||||
guint use_diff : 1;
|
||||
} Collect;
|
||||
|
||||
G_DEFINE_TYPE (SysprofDuplexVisualizer, sysprof_duplex_visualizer, SYSPROF_TYPE_VISUALIZER)
|
||||
|
||||
static bool
|
||||
collect_ranges_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer data)
|
||||
{
|
||||
Collect *state = data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (state != NULL);
|
||||
g_assert (state->cache != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
const SysprofCaptureCounterSet *set = (gconstpointer)frame;
|
||||
|
||||
for (guint i = 0; i < set->n_values; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *values = &set->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
|
||||
{
|
||||
gint64 v64 = values->values[j].v64;
|
||||
guint id = values->ids[j];
|
||||
gint64 max_change = 0;
|
||||
|
||||
if (id == 0)
|
||||
break;
|
||||
|
||||
if (id == state->rx)
|
||||
{
|
||||
if (state->last_rx_val != G_MININT64)
|
||||
max_change = v64 - state->last_rx_val;
|
||||
state->last_rx_val = v64;
|
||||
}
|
||||
else if (id == state->tx)
|
||||
{
|
||||
if (state->last_tx_val != G_MININT64)
|
||||
max_change = v64 - state->last_tx_val;
|
||||
state->last_tx_val = v64;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (max_change > state->max_change)
|
||||
state->max_change = max_change;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_values_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer data)
|
||||
{
|
||||
Collect *state = data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (state != NULL);
|
||||
g_assert (state->cache != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
const SysprofCaptureCounterSet *set = (gconstpointer)frame;
|
||||
gdouble x = (frame->time - state->begin_time) / (gdouble)state->duration;
|
||||
|
||||
for (guint i = 0; i < set->n_values; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *values = &set->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
|
||||
{
|
||||
gint64 v64 = values->values[j].v64;
|
||||
guint id = values->ids[j];
|
||||
gint64 val = v64;
|
||||
gdouble y = 0.5;
|
||||
|
||||
if (id == 0)
|
||||
break;
|
||||
|
||||
if (id == state->rx)
|
||||
{
|
||||
if (state->use_diff)
|
||||
{
|
||||
if (state->last_rx_val == G_MININT64)
|
||||
val = 0;
|
||||
else
|
||||
val -= state->last_rx_val;
|
||||
}
|
||||
|
||||
/* RX goes upward from half point */
|
||||
if (state->max_change != 0)
|
||||
y += (gdouble)val / (gdouble)state->max_change / 2.0;
|
||||
|
||||
state->last_rx_val = v64;
|
||||
}
|
||||
else if (id == state->tx)
|
||||
{
|
||||
if (state->use_diff)
|
||||
{
|
||||
if (state->last_tx_val == G_MININT64)
|
||||
val = 0;
|
||||
else
|
||||
val -= state->last_tx_val;
|
||||
}
|
||||
|
||||
/* TX goes downward from half point */
|
||||
if (state->max_change != 0)
|
||||
y -= (gdouble)val / (gdouble)state->max_change / 2.0;
|
||||
|
||||
state->last_tx_val = v64;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
point_cache_add_point_to_set (state->cache, id, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofCaptureCursor *cursor = task_data;
|
||||
SysprofDuplexVisualizer *self = source_object;
|
||||
Collect state = {0};
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_assert (cursor != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
state.cache = point_cache_new ();
|
||||
state.begin_time = self->begin_time;
|
||||
state.duration = self->duration;
|
||||
state.rx = g_atomic_int_get (&self->rx_counter);
|
||||
state.tx = g_atomic_int_get (&self->tx_counter);
|
||||
state.last_rx_val = G_MININT64;
|
||||
state.last_tx_val = G_MININT64;
|
||||
state.max_change = 0;
|
||||
state.use_diff = self->use_diff;
|
||||
|
||||
point_cache_add_set (state.cache, state.rx);
|
||||
point_cache_add_set (state.cache, state.tx);
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, collect_ranges_cb, &state);
|
||||
sysprof_capture_cursor_reset (cursor);
|
||||
|
||||
/* Give just a bit of overhead */
|
||||
state.max_change *= 1.1;
|
||||
|
||||
/* Reset for calculations */
|
||||
state.last_rx_val = G_MININT64;
|
||||
state.last_tx_val = G_MININT64;
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, collect_values_cb, &state);
|
||||
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&state.cache),
|
||||
(GDestroyNotify) point_cache_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
load_data_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)object;
|
||||
g_autoptr(PointCache) pc = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
if ((pc = g_task_propagate_pointer (G_TASK (result), NULL)))
|
||||
{
|
||||
g_clear_pointer (&self->cache, point_cache_unref);
|
||||
self->cache = g_steal_pointer (&pc);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_set_reader (SysprofVisualizer *visualizer,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)visualizer;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
SysprofCaptureCondition *c;
|
||||
guint counters[2];
|
||||
|
||||
g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_assert (reader != NULL);
|
||||
|
||||
self->begin_time = sysprof_capture_reader_get_start_time (reader);
|
||||
self->duration = sysprof_capture_reader_get_end_time (reader)
|
||||
- sysprof_capture_reader_get_start_time (reader);
|
||||
|
||||
counters[0] = self->rx_counter;
|
||||
counters[1] = self->tx_counter;
|
||||
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
c = sysprof_capture_condition_new_where_counter_in (G_N_ELEMENTS (counters), counters);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&c));
|
||||
|
||||
task = g_task_new (self, NULL, load_data_cb, NULL);
|
||||
g_task_set_source_tag (task, sysprof_duplex_visualizer_set_reader);
|
||||
g_task_set_task_data (task,
|
||||
g_steal_pointer (&cursor),
|
||||
(GDestroyNotify)sysprof_capture_cursor_unref);
|
||||
g_task_run_in_thread (task, sysprof_duplex_visualizer_worker);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
static const gdouble dashes[] = { 1.0, 2.0 };
|
||||
SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)widget;
|
||||
PangoFontDescription *font_desc;
|
||||
GtkStyleContext *style_context;
|
||||
PangoLayout *layout;
|
||||
cairo_t *cr;
|
||||
GtkAllocation alloc;
|
||||
GdkRGBA fg;
|
||||
guint mid;
|
||||
|
||||
g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_assert (snapshot != NULL);
|
||||
|
||||
/* FIXME: This should all be drawn offscreen and then drawn to the snapshot
|
||||
* using GdkMemoryTexture so that we can avoid extra GPU uploads.
|
||||
*/
|
||||
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
mid = alloc.height / 2;
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_duplex_visualizer_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
|
||||
|
||||
style_context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_get_color (style_context, &fg);
|
||||
fg.alpha *= 0.4;
|
||||
|
||||
/* Draw our center line */
|
||||
cairo_save (cr);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
|
||||
cairo_move_to (cr, 0, mid);
|
||||
cairo_line_to (cr, alloc.width, mid);
|
||||
gdk_cairo_set_source_rgba (cr, &fg);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
if (self->cache != NULL)
|
||||
{
|
||||
g_autofree SysprofVisualizerAbsolutePoint *points = NULL;
|
||||
const Point *fpoints;
|
||||
guint n_fpoints = 0;
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
if (self->rx_rgba_set)
|
||||
gdk_cairo_set_source_rgba (cr, &self->rx_rgba);
|
||||
|
||||
fpoints = point_cache_get_points (self->cache, self->rx_counter, &n_fpoints);
|
||||
|
||||
if (n_fpoints > 0)
|
||||
{
|
||||
GdkRGBA rgba = self->rx_rgba;
|
||||
gdouble last_x;
|
||||
gdouble last_y;
|
||||
guint p;
|
||||
|
||||
points = g_realloc_n (points, n_fpoints, sizeof *points);
|
||||
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
|
||||
(const SysprofVisualizerRelativePoint *)fpoints,
|
||||
n_fpoints,
|
||||
points,
|
||||
n_fpoints);
|
||||
|
||||
/* Skip past data that we won't see anyway */
|
||||
#if 0
|
||||
for (p = 0; p < n_fpoints; p++)
|
||||
{
|
||||
if (points[p].x >= clip.x)
|
||||
break;
|
||||
}
|
||||
|
||||
if (p >= n_fpoints)
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* But get at least one data point to anchor out of view */
|
||||
if (p > 0)
|
||||
p--;
|
||||
|
||||
last_x = points[p].x;
|
||||
last_y = points[p].y;
|
||||
|
||||
cairo_move_to (cr, last_x, mid);
|
||||
cairo_line_to (cr, last_x, last_y);
|
||||
|
||||
for (guint i = p + 1; i < n_fpoints; i++)
|
||||
{
|
||||
cairo_curve_to (cr,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
last_y,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
points[i].y,
|
||||
points[i].x,
|
||||
points[i].y);
|
||||
|
||||
last_x = points[i].x;
|
||||
last_y = points[i].y;
|
||||
|
||||
#if 0
|
||||
if (points[i].x > clip.x + clip.width)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cairo_line_to (cr, last_x, mid);
|
||||
cairo_close_path (cr);
|
||||
cairo_stroke_preserve (cr);
|
||||
rgba.alpha *= 0.5;
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
/* AND NOW Tx */
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
if (self->tx_rgba_set)
|
||||
gdk_cairo_set_source_rgba (cr, &self->tx_rgba);
|
||||
|
||||
fpoints = point_cache_get_points (self->cache, self->tx_counter, &n_fpoints);
|
||||
|
||||
if (n_fpoints > 0)
|
||||
{
|
||||
GdkRGBA rgba = self->tx_rgba;
|
||||
gdouble last_x;
|
||||
gdouble last_y;
|
||||
guint p;
|
||||
|
||||
points = g_realloc_n (points, n_fpoints, sizeof *points);
|
||||
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
|
||||
(const SysprofVisualizerRelativePoint *)fpoints,
|
||||
n_fpoints,
|
||||
points,
|
||||
n_fpoints);
|
||||
|
||||
#if 0
|
||||
/* Skip past data that we won't see anyway */
|
||||
for (p = 0; p < n_fpoints; p++)
|
||||
{
|
||||
if (points[p].x >= clip.x)
|
||||
break;
|
||||
}
|
||||
|
||||
if (p >= n_fpoints)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
/* But get at least one data point to anchor out of view */
|
||||
if (p > 0)
|
||||
p--;
|
||||
|
||||
last_x = points[p].x;
|
||||
last_y = points[p].y;
|
||||
|
||||
cairo_move_to (cr, last_x, mid);
|
||||
cairo_line_to (cr, last_x, last_y);
|
||||
|
||||
for (guint i = p + 1; i < n_fpoints; i++)
|
||||
{
|
||||
cairo_curve_to (cr,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
last_y,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
points[i].y,
|
||||
points[i].x,
|
||||
points[i].y);
|
||||
|
||||
last_x = points[i].x;
|
||||
last_y = points[i].y;
|
||||
|
||||
#if 0
|
||||
if (points[i].x > clip.x + clip.width)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cairo_line_to (cr, last_x, mid);
|
||||
cairo_close_path (cr);
|
||||
cairo_stroke_preserve (cr);
|
||||
rgba.alpha *= 0.5;
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, "");
|
||||
|
||||
font_desc = pango_font_description_new ();
|
||||
pango_font_description_set_family_static (font_desc, "Monospace");
|
||||
pango_font_description_set_absolute_size (font_desc, LABEL_HEIGHT_PX * PANGO_SCALE);
|
||||
pango_layout_set_font_description (layout, font_desc);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &fg);
|
||||
|
||||
cairo_move_to (cr, 2, 2);
|
||||
if (self->rx_label != NULL)
|
||||
pango_layout_set_text (layout, self->rx_label, -1);
|
||||
else
|
||||
pango_layout_set_text (layout, "RX", 2);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
cairo_move_to (cr, 2, mid + 2);
|
||||
if (self->tx_label != NULL)
|
||||
pango_layout_set_text (layout, self->tx_label, -1);
|
||||
else
|
||||
pango_layout_set_text (layout, "TX", 2);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
pango_font_description_free (font_desc);
|
||||
g_object_unref (layout);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)object;
|
||||
|
||||
g_clear_pointer (&self->cache, point_cache_unref);
|
||||
g_clear_pointer (&self->rx_label, g_free);
|
||||
g_clear_pointer (&self->tx_label, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_duplex_visualizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_class_init (SysprofDuplexVisualizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_duplex_visualizer_finalize;
|
||||
|
||||
widget_class->snapshot = sysprof_duplex_visualizer_snapshot;
|
||||
|
||||
visualizer_class->set_reader = sysprof_duplex_visualizer_set_reader;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_init (SysprofDuplexVisualizer *self)
|
||||
{
|
||||
self->use_diff = TRUE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
sysprof_duplex_visualizer_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_DUPLEX_VISUALIZER, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_duplex_visualizer_set_counters (SysprofDuplexVisualizer *self,
|
||||
guint rx_counter,
|
||||
guint tx_counter)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_return_if_fail (rx_counter != 0);
|
||||
g_return_if_fail (tx_counter != 0);
|
||||
|
||||
self->rx_counter = rx_counter;
|
||||
self->tx_counter = tx_counter;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_duplex_visualizer_set_colors (SysprofDuplexVisualizer *self,
|
||||
const GdkRGBA *rx_rgba,
|
||||
const GdkRGBA *tx_rgba)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
|
||||
if (rx_rgba)
|
||||
self->rx_rgba = *rx_rgba;
|
||||
self->rx_rgba_set = !!rx_rgba;
|
||||
|
||||
if (tx_rgba)
|
||||
self->tx_rgba = *tx_rgba;
|
||||
self->tx_rgba_set = !!tx_rgba;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_duplex_visualizer_get_use_diff (SysprofDuplexVisualizer *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self), FALSE);
|
||||
|
||||
return self->use_diff;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_duplex_visualizer_set_use_diff (SysprofDuplexVisualizer *self,
|
||||
gboolean use_diff)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
|
||||
self->use_diff = !!use_diff;
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_duplex_visualizer_set_labels (SysprofDuplexVisualizer *self,
|
||||
const gchar *rx_label,
|
||||
const gchar *tx_label)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
|
||||
if (g_strcmp0 (rx_label, self->rx_label) != 0)
|
||||
{
|
||||
g_free (self->rx_label);
|
||||
self->rx_label = g_strdup (rx_label);
|
||||
}
|
||||
|
||||
if (g_strcmp0 (tx_label, self->tx_label) != 0)
|
||||
{
|
||||
g_free (self->tx_label);
|
||||
self->tx_label = g_strdup (tx_label);
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
/* sysprof-duplex-visualizer.h
|
||||
*
|
||||
* Copyright 2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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 "sysprof-visualizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DUPLEX_VISUALIZER (sysprof_duplex_visualizer_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDuplexVisualizer, sysprof_duplex_visualizer, SYSPROF, DUPLEX_VISUALIZER, SysprofVisualizer)
|
||||
|
||||
GtkWidget *sysprof_duplex_visualizer_new (void);
|
||||
gboolean sysprof_duplex_visualizer_get_use_diff (SysprofDuplexVisualizer *self);
|
||||
void sysprof_duplex_visualizer_set_use_diff (SysprofDuplexVisualizer *self,
|
||||
gboolean use_diff);
|
||||
void sysprof_duplex_visualizer_set_labels (SysprofDuplexVisualizer *self,
|
||||
const gchar *rx_label,
|
||||
const gchar *tx_label);
|
||||
void sysprof_duplex_visualizer_set_counters (SysprofDuplexVisualizer *self,
|
||||
guint rx_counter,
|
||||
guint tx_counter);
|
||||
void sysprof_duplex_visualizer_set_colors (SysprofDuplexVisualizer *self,
|
||||
const GdkRGBA *rx_rgba,
|
||||
const GdkRGBA *tx_rgba);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,277 +0,0 @@
|
||||
/* sysprof-environ-editor-row.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-environ-editor-row"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-environ-editor-row.h"
|
||||
|
||||
struct _SysprofEnvironEditorRow
|
||||
{
|
||||
GtkListBoxRow parent_instance;
|
||||
|
||||
SysprofEnvironVariable *variable;
|
||||
|
||||
GtkEntry *key_entry;
|
||||
GtkEntry *value_entry;
|
||||
GtkButton *delete_button;
|
||||
|
||||
GBinding *key_binding;
|
||||
GBinding *value_binding;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_VARIABLE,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
enum {
|
||||
DELETE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofEnvironEditorRow, sysprof_environ_editor_row, GTK_TYPE_LIST_BOX_ROW)
|
||||
|
||||
static GParamSpec *properties [LAST_PROP];
|
||||
static guint signals [LAST_SIGNAL];
|
||||
|
||||
static gboolean
|
||||
null_safe_mapping (GBinding *binding,
|
||||
const GValue *from_value,
|
||||
GValue *to_value,
|
||||
gpointer user_data)
|
||||
{
|
||||
const gchar *str = g_value_get_string (from_value);
|
||||
g_value_set_string (to_value, str ?: "");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_connect (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_VARIABLE (self->variable));
|
||||
|
||||
self->key_binding =
|
||||
g_object_bind_property_full (self->variable, "key", self->key_entry, "text",
|
||||
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
|
||||
null_safe_mapping, NULL, NULL, NULL);
|
||||
|
||||
self->value_binding =
|
||||
g_object_bind_property_full (self->variable, "value", self->value_entry, "text",
|
||||
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
|
||||
null_safe_mapping, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_disconnect (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_VARIABLE (self->variable));
|
||||
|
||||
g_clear_pointer (&self->key_binding, g_binding_unbind);
|
||||
g_clear_pointer (&self->value_binding, g_binding_unbind);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_button_clicked (GtkButton *button,
|
||||
SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_assert (GTK_IS_BUTTON (button));
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
|
||||
g_signal_emit (self, signals [DELETE], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
key_entry_activate (GtkWidget *entry,
|
||||
SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_assert (GTK_IS_ENTRY (entry));
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self->value_entry));
|
||||
}
|
||||
|
||||
static void
|
||||
value_entry_activate (GtkWidget *entry,
|
||||
SysprofEnvironEditorRow *self)
|
||||
{
|
||||
GtkWidget *parent;
|
||||
|
||||
g_assert (GTK_IS_ENTRY (entry));
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self));
|
||||
parent = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_LIST_BOX);
|
||||
g_signal_emit_by_name (parent, "move-cursor", GTK_MOVEMENT_DISPLAY_LINES, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_dispose (GObject *object)
|
||||
{
|
||||
SysprofEnvironEditorRow *self = (SysprofEnvironEditorRow *)object;
|
||||
|
||||
if (self->variable != NULL)
|
||||
{
|
||||
sysprof_environ_editor_row_disconnect (self);
|
||||
g_clear_object (&self->variable);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (sysprof_environ_editor_row_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironEditorRow *self = SYSPROF_ENVIRON_EDITOR_ROW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_VARIABLE:
|
||||
g_value_set_object (value, sysprof_environ_editor_row_get_variable (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironEditorRow *self = SYSPROF_ENVIRON_EDITOR_ROW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_VARIABLE:
|
||||
sysprof_environ_editor_row_set_variable (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_class_init (SysprofEnvironEditorRowClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_environ_editor_row_dispose;
|
||||
object_class->get_property = sysprof_environ_editor_row_get_property;
|
||||
object_class->set_property = sysprof_environ_editor_row_set_property;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-environ-editor-row.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, delete_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, key_entry);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, value_entry);
|
||||
|
||||
properties [PROP_VARIABLE] =
|
||||
g_param_spec_object ("variable",
|
||||
"Variable",
|
||||
"Variable",
|
||||
SYSPROF_TYPE_ENVIRON_VARIABLE,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, properties);
|
||||
|
||||
signals [DELETE] =
|
||||
g_signal_new ("delete",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_init (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
g_signal_connect (self->delete_button,
|
||||
"clicked",
|
||||
G_CALLBACK (delete_button_clicked),
|
||||
self);
|
||||
|
||||
g_signal_connect (self->key_entry,
|
||||
"activate",
|
||||
G_CALLBACK (key_entry_activate),
|
||||
self);
|
||||
|
||||
g_signal_connect (self->value_entry,
|
||||
"activate",
|
||||
G_CALLBACK (value_entry_activate),
|
||||
self);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_environ_editor_row_get_variable:
|
||||
*
|
||||
* Returns: (transfer none) (nullable): An #SysprofEnvironVariable.
|
||||
*/
|
||||
SysprofEnvironVariable *
|
||||
sysprof_environ_editor_row_get_variable (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self), NULL);
|
||||
|
||||
return self->variable;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_editor_row_set_variable (SysprofEnvironEditorRow *self,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
g_return_if_fail (!variable || SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
if (variable != self->variable)
|
||||
{
|
||||
if (self->variable != NULL)
|
||||
{
|
||||
sysprof_environ_editor_row_disconnect (self);
|
||||
g_clear_object (&self->variable);
|
||||
}
|
||||
|
||||
if (variable != NULL)
|
||||
{
|
||||
self->variable = g_object_ref (variable);
|
||||
sysprof_environ_editor_row_connect (self);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VARIABLE]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_editor_row_start_editing (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self->key_entry));
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
/* ide-environ-editor-row.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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 "sysprof-environ-variable.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ENVIRON_EDITOR_ROW (sysprof_environ_editor_row_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofEnvironEditorRow, sysprof_environ_editor_row, SYSPROF, ENVIRON_EDITOR_ROW, GtkListBoxRow)
|
||||
|
||||
SysprofEnvironVariable *sysprof_environ_editor_row_get_variable (SysprofEnvironEditorRow *self);
|
||||
void sysprof_environ_editor_row_set_variable (SysprofEnvironEditorRow *self,
|
||||
SysprofEnvironVariable *variable);
|
||||
void sysprof_environ_editor_row_start_editing (SysprofEnvironEditorRow *self);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SysprofEnvironEditorRow" parent="GtkListBoxRow">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="key_entry">
|
||||
<property name="margin-start">3</property>
|
||||
<property name="has-frame">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="eq_label">
|
||||
<property name="label">=</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="value_entry">
|
||||
<property name="hexpand">True</property>
|
||||
<property name="has-frame">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="delete_button">
|
||||
<property name="tooltip-text" translatable="yes">Remove environment variable</property>
|
||||
<property name="icon-name">list-remove-symbolic</property>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,343 +0,0 @@
|
||||
/* sysprof-environ-editor.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-environ-editor"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-environ-editor.h"
|
||||
#include "sysprof-environ-editor-row.h"
|
||||
#include "sysprof-theme-manager.h"
|
||||
|
||||
struct _SysprofEnvironEditor
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
GtkListBox *list_box;
|
||||
SysprofEnviron *environ;
|
||||
GtkWidget *dummy_row;
|
||||
SysprofEnvironVariable *dummy;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofEnvironEditor, sysprof_environ_editor, GTK_TYPE_WIDGET)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ENVIRON,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_delete_row (SysprofEnvironEditor *self,
|
||||
SysprofEnvironEditorRow *row)
|
||||
{
|
||||
SysprofEnvironVariable *variable;
|
||||
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (row));
|
||||
|
||||
variable = sysprof_environ_editor_row_get_variable (row);
|
||||
sysprof_environ_remove (self->environ, variable);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
sysprof_environ_editor_create_dummy_row (SysprofEnvironEditor *self)
|
||||
{
|
||||
GtkWidget *row;
|
||||
GtkWidget *label;
|
||||
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
|
||||
label = g_object_new (GTK_TYPE_LABEL,
|
||||
"label", _("New environment variable…"),
|
||||
"margin-start", 6,
|
||||
"margin-end", 6,
|
||||
"margin-top", 6,
|
||||
"margin-bottom", 6,
|
||||
"visible", TRUE,
|
||||
"xalign", 0.0f,
|
||||
NULL);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
|
||||
|
||||
row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
|
||||
"child", label,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
sysprof_environ_editor_create_row (gpointer item,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofEnvironVariable *variable = item;
|
||||
SysprofEnvironEditor *self = user_data;
|
||||
SysprofEnvironEditorRow *row;
|
||||
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_ENVIRON_EDITOR_ROW,
|
||||
"variable", variable,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
g_signal_connect_object (row,
|
||||
"delete",
|
||||
G_CALLBACK (sysprof_environ_editor_delete_row),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
return GTK_WIDGET (row);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_disconnect (SysprofEnvironEditor *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON (self->environ));
|
||||
|
||||
gtk_list_box_bind_model (self->list_box, NULL, NULL, NULL, NULL);
|
||||
g_clear_object (&self->dummy);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_connect (SysprofEnvironEditor *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON (self->environ));
|
||||
|
||||
gtk_list_box_bind_model (self->list_box,
|
||||
G_LIST_MODEL (self->environ),
|
||||
sysprof_environ_editor_create_row, self, NULL);
|
||||
|
||||
self->dummy_row = sysprof_environ_editor_create_dummy_row (self);
|
||||
gtk_list_box_append (self->list_box, self->dummy_row);
|
||||
}
|
||||
|
||||
static void
|
||||
find_row_cb (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
struct {
|
||||
SysprofEnvironVariable *variable;
|
||||
SysprofEnvironEditorRow *row;
|
||||
} *lookup = data;
|
||||
|
||||
g_assert (lookup != NULL);
|
||||
g_assert (GTK_IS_LIST_BOX_ROW (widget));
|
||||
|
||||
if (SYSPROF_IS_ENVIRON_EDITOR_ROW (widget))
|
||||
{
|
||||
SysprofEnvironVariable *variable;
|
||||
|
||||
variable = sysprof_environ_editor_row_get_variable (SYSPROF_ENVIRON_EDITOR_ROW (widget));
|
||||
|
||||
if (variable == lookup->variable)
|
||||
lookup->row = SYSPROF_ENVIRON_EDITOR_ROW (widget);
|
||||
}
|
||||
}
|
||||
|
||||
static SysprofEnvironEditorRow *
|
||||
find_row (SysprofEnvironEditor *self,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
struct {
|
||||
SysprofEnvironVariable *variable;
|
||||
SysprofEnvironEditorRow *row;
|
||||
} lookup = { variable, NULL };
|
||||
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self->list_box));
|
||||
child;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
find_row_cb (child, &lookup);
|
||||
|
||||
return lookup.row;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_activated (SysprofEnvironEditor *self,
|
||||
GtkListBoxRow *row,
|
||||
GtkListBox *list_box)
|
||||
{
|
||||
g_assert (GTK_IS_LIST_BOX (list_box));
|
||||
g_assert (GTK_IS_LIST_BOX_ROW (row));
|
||||
|
||||
if (self->environ == NULL)
|
||||
return;
|
||||
|
||||
if (self->dummy_row == GTK_WIDGET (row))
|
||||
{
|
||||
g_autoptr(SysprofEnvironVariable) variable = NULL;
|
||||
|
||||
variable = sysprof_environ_variable_new (NULL, NULL);
|
||||
sysprof_environ_append (self->environ, variable);
|
||||
sysprof_environ_editor_row_start_editing (find_row (self, variable));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_dispose (GObject *object)
|
||||
{
|
||||
SysprofEnvironEditor *self = (SysprofEnvironEditor *)object;
|
||||
|
||||
if (self->list_box)
|
||||
{
|
||||
gtk_widget_unparent (GTK_WIDGET (self->list_box));
|
||||
self->list_box = NULL;
|
||||
}
|
||||
|
||||
g_clear_object (&self->environ);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_environ_editor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironEditor *self = SYSPROF_ENVIRON_EDITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ENVIRON:
|
||||
g_value_set_object (value, sysprof_environ_editor_get_environ (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironEditor *self = SYSPROF_ENVIRON_EDITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ENVIRON:
|
||||
sysprof_environ_editor_set_environ (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_class_init (SysprofEnvironEditorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofThemeManager *theme_manager = sysprof_theme_manager_get_default ();
|
||||
|
||||
object_class->dispose = sysprof_environ_editor_dispose;
|
||||
object_class->get_property = sysprof_environ_editor_get_property;
|
||||
object_class->set_property = sysprof_environ_editor_set_property;
|
||||
|
||||
properties [PROP_ENVIRON] =
|
||||
g_param_spec_object ("environ",
|
||||
"Environment",
|
||||
"Environment",
|
||||
SYSPROF_TYPE_ENVIRON,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
|
||||
sysprof_theme_manager_register_resource (theme_manager, NULL, NULL, "/org/gnome/sysprof/css/SysprofEnvironEditor-shared.css");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_init (SysprofEnvironEditor *self)
|
||||
{
|
||||
self->list_box = GTK_LIST_BOX (gtk_list_box_new ());
|
||||
gtk_widget_set_parent (GTK_WIDGET (self->list_box), GTK_WIDGET (self));
|
||||
|
||||
gtk_list_box_set_selection_mode (self->list_box, GTK_SELECTION_NONE);
|
||||
|
||||
gtk_widget_add_css_class (GTK_WIDGET (self), "environ-editor");
|
||||
|
||||
g_signal_connect_object (self->list_box,
|
||||
"row-activated",
|
||||
G_CALLBACK (sysprof_environ_editor_row_activated),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
sysprof_environ_editor_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ENVIRON_EDITOR, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_editor_set_environ (SysprofEnvironEditor *self,
|
||||
SysprofEnviron *environ_)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (environ_));
|
||||
|
||||
if (self->environ != environ_)
|
||||
{
|
||||
if (self->environ != NULL)
|
||||
{
|
||||
sysprof_environ_editor_disconnect (self);
|
||||
g_clear_object (&self->environ);
|
||||
}
|
||||
|
||||
if (environ_ != NULL)
|
||||
{
|
||||
self->environ = g_object_ref (environ_);
|
||||
sysprof_environ_editor_connect (self);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENVIRON]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_environ_editor_get_environ:
|
||||
*
|
||||
* Returns: (nullable) (transfer none): An #SysprofEnviron or %NULL.
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofEnviron *
|
||||
sysprof_environ_editor_get_environ (SysprofEnvironEditor *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON_EDITOR (self), NULL);
|
||||
|
||||
return self->environ;
|
||||
}
|
||||
@ -1,185 +0,0 @@
|
||||
/* sysprof-environ-variable.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-environ-variable"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-environ-variable.h"
|
||||
|
||||
struct _SysprofEnvironVariable
|
||||
{
|
||||
GObject parent_instance;
|
||||
gchar *key;
|
||||
gchar *value;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofEnvironVariable, sysprof_environ_variable, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_KEY,
|
||||
PROP_VALUE,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *properties [LAST_PROP];
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_finalize (GObject *object)
|
||||
{
|
||||
SysprofEnvironVariable *self = (SysprofEnvironVariable *)object;
|
||||
|
||||
g_clear_pointer (&self->key, g_free);
|
||||
g_clear_pointer (&self->value, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_environ_variable_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironVariable *self = SYSPROF_ENVIRON_VARIABLE(object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_KEY:
|
||||
g_value_set_string (value, self->key);
|
||||
break;
|
||||
|
||||
case PROP_VALUE:
|
||||
g_value_set_string (value, self->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironVariable *self = SYSPROF_ENVIRON_VARIABLE(object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_KEY:
|
||||
sysprof_environ_variable_set_key (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_VALUE:
|
||||
sysprof_environ_variable_set_value (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_class_init (SysprofEnvironVariableClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_environ_variable_finalize;
|
||||
object_class->get_property = sysprof_environ_variable_get_property;
|
||||
object_class->set_property = sysprof_environ_variable_set_property;
|
||||
|
||||
properties [PROP_KEY] =
|
||||
g_param_spec_string ("key",
|
||||
"Key",
|
||||
"The key for the environment variable",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_VALUE] =
|
||||
g_param_spec_string ("value",
|
||||
"Value",
|
||||
"The value for the environment variable",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_init (SysprofEnvironVariable *self)
|
||||
{
|
||||
}
|
||||
|
||||
const gchar *
|
||||
sysprof_environ_variable_get_key (SysprofEnvironVariable *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self), NULL);
|
||||
|
||||
return self->key;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_variable_set_key (SysprofEnvironVariable *self,
|
||||
const gchar *key)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self));
|
||||
|
||||
if (g_strcmp0 (key, self->key) != 0)
|
||||
{
|
||||
g_free (self->key);
|
||||
self->key = g_strdup (key);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_KEY]);
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
sysprof_environ_variable_get_value (SysprofEnvironVariable *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self), NULL);
|
||||
|
||||
return self->value;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_variable_set_value (SysprofEnvironVariable *self,
|
||||
const gchar *value)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self));
|
||||
|
||||
if (g_strcmp0 (value, self->value) != 0)
|
||||
{
|
||||
g_free (self->value);
|
||||
self->value = g_strdup (value);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VALUE]);
|
||||
}
|
||||
}
|
||||
|
||||
SysprofEnvironVariable *
|
||||
sysprof_environ_variable_new (const gchar *key,
|
||||
const gchar *value)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ENVIRON_VARIABLE,
|
||||
"key", key,
|
||||
"value", value,
|
||||
NULL);
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
/* sysprof-environ-variable.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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 <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ENVIRON_VARIABLE (sysprof_environ_variable_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofEnvironVariable, sysprof_environ_variable, SYSPROF, ENVIRON_VARIABLE, GObject)
|
||||
|
||||
SysprofEnvironVariable *sysprof_environ_variable_new (const gchar *key,
|
||||
const gchar *value);
|
||||
const gchar *sysprof_environ_variable_get_key (SysprofEnvironVariable *self);
|
||||
void sysprof_environ_variable_set_key (SysprofEnvironVariable *self,
|
||||
const gchar *key);
|
||||
const gchar *sysprof_environ_variable_get_value (SysprofEnvironVariable *self);
|
||||
void sysprof_environ_variable_set_value (SysprofEnvironVariable *self,
|
||||
const gchar *value);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,379 +0,0 @@
|
||||
/* sysprof-environ.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-environ"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-environ.h"
|
||||
#include "sysprof-environ-variable.h"
|
||||
|
||||
struct _SysprofEnviron
|
||||
{
|
||||
GObject parent_instance;
|
||||
GPtrArray *variables;
|
||||
};
|
||||
|
||||
static void list_model_iface_init (GListModelInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (SysprofEnviron, sysprof_environ, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals [LAST_SIGNAL];
|
||||
|
||||
static void
|
||||
sysprof_environ_finalize (GObject *object)
|
||||
{
|
||||
SysprofEnviron *self = (SysprofEnviron *)object;
|
||||
|
||||
g_clear_pointer (&self->variables, g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_environ_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_class_init (SysprofEnvironClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_environ_finalize;
|
||||
|
||||
signals [CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
g_signal_set_va_marshaller (signals [CHANGED],
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
g_cclosure_marshal_VOID__VOIDv);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_items_changed (SysprofEnviron *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON (self));
|
||||
|
||||
g_signal_emit (self, signals [CHANGED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_init (SysprofEnviron *self)
|
||||
{
|
||||
self->variables = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
g_signal_connect (self,
|
||||
"items-changed",
|
||||
G_CALLBACK (sysprof_environ_items_changed),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_environ_get_item_type (GListModel *model)
|
||||
{
|
||||
return SYSPROF_TYPE_ENVIRON_VARIABLE;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_environ_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofEnviron *self = (SysprofEnviron *)model;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
|
||||
g_return_val_if_fail (position < self->variables->len, NULL);
|
||||
|
||||
return g_object_ref (g_ptr_array_index (self->variables, position));
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_environ_get_n_items (GListModel *model)
|
||||
{
|
||||
SysprofEnviron *self = (SysprofEnviron *)model;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), 0);
|
||||
|
||||
return self->variables->len;
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_n_items = sysprof_environ_get_n_items;
|
||||
iface->get_item = sysprof_environ_get_item;
|
||||
iface->get_item_type = sysprof_environ_get_item_type;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_notify (SysprofEnviron *self,
|
||||
GParamSpec *pspec,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON (self));
|
||||
|
||||
g_signal_emit (self, signals [CHANGED], 0);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_setenv (SysprofEnviron *self,
|
||||
const gchar *key,
|
||||
const gchar *value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (self));
|
||||
g_return_if_fail (key != NULL);
|
||||
|
||||
for (i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
|
||||
const gchar *var_key = sysprof_environ_variable_get_key (var);
|
||||
|
||||
if (g_strcmp0 (key, var_key) == 0)
|
||||
{
|
||||
if (value == NULL)
|
||||
{
|
||||
g_ptr_array_remove_index (self->variables, i);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
sysprof_environ_variable_set_value (var, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (value != NULL)
|
||||
{
|
||||
SysprofEnvironVariable *var;
|
||||
guint position = self->variables->len;
|
||||
|
||||
var = g_object_new (SYSPROF_TYPE_ENVIRON_VARIABLE,
|
||||
"key", key,
|
||||
"value", value,
|
||||
NULL);
|
||||
g_signal_connect_object (var,
|
||||
"notify",
|
||||
G_CALLBACK (sysprof_environ_variable_notify),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_ptr_array_add (self->variables, var);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
sysprof_environ_getenv (SysprofEnviron *self,
|
||||
const gchar *key)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
|
||||
g_return_val_if_fail (key != NULL, NULL);
|
||||
|
||||
for (i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
|
||||
const gchar *var_key = sysprof_environ_variable_get_key (var);
|
||||
|
||||
if (g_strcmp0 (key, var_key) == 0)
|
||||
return sysprof_environ_variable_get_value (var);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_environ_get_environ:
|
||||
* @self: An #SysprofEnviron
|
||||
*
|
||||
* Gets the environment as a set of key=value pairs, suitable for use
|
||||
* in various GLib process functions.
|
||||
*
|
||||
* Returns: (transfer full): A newly allocated string array.
|
||||
*
|
||||
* Since: 3.32
|
||||
*/
|
||||
gchar **
|
||||
sysprof_environ_get_environ (SysprofEnviron *self)
|
||||
{
|
||||
GPtrArray *ar;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
|
||||
|
||||
ar = g_ptr_array_new ();
|
||||
|
||||
for (i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
|
||||
const gchar *key = sysprof_environ_variable_get_key (var);
|
||||
const gchar *value = sysprof_environ_variable_get_value (var);
|
||||
|
||||
if (value == NULL)
|
||||
value = "";
|
||||
|
||||
if (key != NULL)
|
||||
g_ptr_array_add (ar, g_strdup_printf ("%s=%s", key, value));
|
||||
}
|
||||
|
||||
g_ptr_array_add (ar, NULL);
|
||||
|
||||
return (gchar **)g_ptr_array_free (ar, FALSE);
|
||||
}
|
||||
|
||||
SysprofEnviron *
|
||||
sysprof_environ_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ENVIRON, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_remove (SysprofEnviron *self,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (self));
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
for (i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *item = g_ptr_array_index (self->variables, i);
|
||||
|
||||
if (item == variable)
|
||||
{
|
||||
g_ptr_array_remove_index (self->variables, i);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_append (SysprofEnviron *self,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
guint position;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (self));
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
position = self->variables->len;
|
||||
|
||||
g_signal_connect_object (variable,
|
||||
"notify",
|
||||
G_CALLBACK (sysprof_environ_variable_notify),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_ptr_array_add (self->variables, g_object_ref (variable));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_environ_copy:
|
||||
* @self: An #SysprofEnviron
|
||||
*
|
||||
* Copies the contents of #SysprofEnviron into a newly allocated #SysprofEnviron.
|
||||
*
|
||||
* Returns: (transfer full): An #SysprofEnviron.
|
||||
*
|
||||
* Since: 3.32
|
||||
*/
|
||||
SysprofEnviron *
|
||||
sysprof_environ_copy (SysprofEnviron *self)
|
||||
{
|
||||
g_autoptr(SysprofEnviron) copy = NULL;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
|
||||
|
||||
copy = sysprof_environ_new ();
|
||||
sysprof_environ_copy_into (self, copy, TRUE);
|
||||
|
||||
return g_steal_pointer (©);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_copy_into (SysprofEnviron *self,
|
||||
SysprofEnviron *dest,
|
||||
gboolean replace)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (self));
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (dest));
|
||||
|
||||
for (guint i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
|
||||
const gchar *key = sysprof_environ_variable_get_key (var);
|
||||
const gchar *value = sysprof_environ_variable_get_value (var);
|
||||
|
||||
if (replace || sysprof_environ_getenv (dest, key) == NULL)
|
||||
sysprof_environ_setenv (dest, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_environ_parse:
|
||||
* @pair: the KEY=VALUE pair
|
||||
* @key: (out) (optional): a location for a @key
|
||||
* @value: (out) (optional): a location for a @value
|
||||
*
|
||||
* Parses a KEY=VALUE style key-pair into @key and @value.
|
||||
*
|
||||
* Returns: %TRUE if @pair was successfully parsed
|
||||
*
|
||||
* Since: 3.32
|
||||
*/
|
||||
gboolean
|
||||
ide_environ_parse (const gchar *pair,
|
||||
gchar **key,
|
||||
gchar **value)
|
||||
{
|
||||
const gchar *eq;
|
||||
|
||||
g_return_val_if_fail (pair != NULL, FALSE);
|
||||
|
||||
if (key != NULL)
|
||||
*key = NULL;
|
||||
|
||||
if (value != NULL)
|
||||
*value = NULL;
|
||||
|
||||
if ((eq = strchr (pair, '=')))
|
||||
{
|
||||
if (key != NULL)
|
||||
*key = g_strndup (pair, eq - pair);
|
||||
|
||||
if (value != NULL)
|
||||
*value = g_strdup (eq + 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/* sysprof-environ.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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 <gio/gio.h>
|
||||
|
||||
#include "sysprof-environ-variable.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ENVIRON (sysprof_environ_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofEnviron, sysprof_environ, SYSPROF, ENVIRON, GObject)
|
||||
|
||||
gboolean ide_environ_parse (const gchar *pair,
|
||||
gchar **key,
|
||||
gchar **value);
|
||||
SysprofEnviron *sysprof_environ_new (void);
|
||||
void sysprof_environ_setenv (SysprofEnviron *self,
|
||||
const gchar *key,
|
||||
const gchar *value);
|
||||
const gchar *sysprof_environ_getenv (SysprofEnviron *self,
|
||||
const gchar *key);
|
||||
gchar **sysprof_environ_get_environ (SysprofEnviron *self);
|
||||
void sysprof_environ_append (SysprofEnviron *self,
|
||||
SysprofEnvironVariable *variable);
|
||||
void sysprof_environ_remove (SysprofEnviron *self,
|
||||
SysprofEnvironVariable *variable);
|
||||
SysprofEnviron *sysprof_environ_copy (SysprofEnviron *self);
|
||||
void sysprof_environ_copy_into (SysprofEnviron *self,
|
||||
SysprofEnviron *dest,
|
||||
gboolean replace);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,62 +0,0 @@
|
||||
/* sysprof-failed-state-view.c
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-failed-state-view.h"
|
||||
|
||||
G_DEFINE_TYPE (SysprofFailedStateView, sysprof_failed_state_view, GTK_TYPE_WIDGET)
|
||||
|
||||
GtkWidget *
|
||||
sysprof_failed_state_view_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_FAILED_STATE_VIEW, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_failed_state_view_dispose (GObject *object)
|
||||
{
|
||||
SysprofFailedStateView *self = (SysprofFailedStateView *)object;
|
||||
GtkWidget *child;
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_failed_state_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_failed_state_view_class_init (SysprofFailedStateViewClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_failed_state_view_dispose;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
gtk_widget_class_set_template_from_resource (widget_class,
|
||||
"/org/gnome/sysprof/ui/sysprof-failed-state-view.ui");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_failed_state_view_init (SysprofFailedStateView *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<interface>
|
||||
<template class="SysprofFailedStateView" parent="GtkWidget">
|
||||
<property name="vexpand">true</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-top">36</property>
|
||||
<property name="margin-bottom">36</property>
|
||||
<property name="margin-start">36</property>
|
||||
<property name="margin-end">36</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<child type="center">
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">computer-fail-symbolic</property>
|
||||
<property name="pixel-size">256</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Ouch, that hurt!</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<attributes>
|
||||
<attribute name="scale" value="2"/>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Something unexpectedly went wrong while trying to profile your system.</property>
|
||||
<property name="use-markup">true</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,909 +0,0 @@
|
||||
/* sysprof-line-visualizer.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-line-visualizer"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "pointcache.h"
|
||||
#include "sysprof-line-visualizer.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/*
|
||||
* Our reader as assigned by the visualizer system.
|
||||
*/
|
||||
SysprofCaptureReader *reader;
|
||||
|
||||
/*
|
||||
* An array of LineInfo which contains information about the counters
|
||||
* we need to render.
|
||||
*/
|
||||
GArray *lines;
|
||||
|
||||
/*
|
||||
* This is our set of cached points to render. Once it is assigned here,
|
||||
* it is immutable (and therefore may be shared with worker processes
|
||||
* that are rendering the points).
|
||||
*/
|
||||
PointCache *cache;
|
||||
|
||||
/* The format for units (such as mHz, Watts, etc). */
|
||||
gchar *units;
|
||||
|
||||
/*
|
||||
* Range of the scale for lower and upper.
|
||||
*/
|
||||
gdouble y_lower;
|
||||
gdouble y_upper;
|
||||
|
||||
/*
|
||||
* If we have a new counter discovered or the reader is set, we might
|
||||
* want to delay loading until we return to the main loop. This can
|
||||
* help us avoid doing duplicate work.
|
||||
*/
|
||||
guint queued_load;
|
||||
|
||||
guint y_lower_set : 1;
|
||||
guint y_upper_set : 1;
|
||||
} SysprofLineVisualizerPrivate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint id;
|
||||
guint type;
|
||||
gdouble line_width;
|
||||
GdkRGBA foreground;
|
||||
GdkRGBA background;
|
||||
guint use_default_style : 1;
|
||||
guint fill : 1;
|
||||
guint use_dash : 1;
|
||||
} LineInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
GArray *lines;
|
||||
PointCache *cache;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
gdouble y_lower;
|
||||
gdouble y_upper;
|
||||
guint y_lower_set : 1;
|
||||
guint y_upper_set : 1;
|
||||
} LoadData;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (SysprofLineVisualizer, sysprof_line_visualizer, SYSPROF_TYPE_VISUALIZER)
|
||||
|
||||
static void sysprof_line_visualizer_load_data_async (SysprofLineVisualizer *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
static PointCache *sysprof_line_visualizer_load_data_finish (SysprofLineVisualizer *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_Y_LOWER,
|
||||
PROP_Y_UPPER,
|
||||
PROP_UNITS,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
static const gdouble dashes[] = { 1.0, 2.0 };
|
||||
|
||||
static void
|
||||
load_data_free (gpointer data)
|
||||
{
|
||||
LoadData *load = data;
|
||||
|
||||
if (load != NULL)
|
||||
{
|
||||
g_clear_pointer (&load->lines, g_array_unref);
|
||||
g_clear_pointer (&load->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_pointer (&load->cache, point_cache_unref);
|
||||
g_slice_free (LoadData, load);
|
||||
}
|
||||
}
|
||||
|
||||
static GArray *
|
||||
copy_array (GArray *ar)
|
||||
{
|
||||
GArray *ret;
|
||||
|
||||
ret = g_array_sized_new (FALSE, FALSE, g_array_get_element_size (ar), ar->len);
|
||||
g_array_set_size (ret, ar->len);
|
||||
memcpy (ret->data, ar->data, ar->len * g_array_get_element_size (ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
static PangoAttrList *attrs = NULL;
|
||||
SysprofLineVisualizer *self = (SysprofLineVisualizer *)widget;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
g_autofree gchar *upper = NULL;
|
||||
GtkStyleContext *style_context;
|
||||
PangoLayout *layout;
|
||||
cairo_t *cr;
|
||||
GtkAllocation alloc;
|
||||
GdkRectangle clip;
|
||||
GdkRGBA foreground;
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (widget));
|
||||
g_assert (snapshot != NULL);
|
||||
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_line_visualizer_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
if (priv->cache == NULL)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
if (!gdk_cairo_get_clip_rectangle (cr, &clip))
|
||||
return ret;
|
||||
#else
|
||||
clip.x = 0;
|
||||
clip.y = 0;
|
||||
clip.width = alloc.width;
|
||||
clip.height = alloc.height;
|
||||
#endif
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
|
||||
|
||||
style_context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_get_color (style_context, &foreground);
|
||||
|
||||
for (guint line = 0; line < priv->lines->len; line++)
|
||||
{
|
||||
g_autofree SysprofVisualizerAbsolutePoint *points = NULL;
|
||||
const LineInfo *line_info = &g_array_index (priv->lines, LineInfo, line);
|
||||
const Point *fpoints;
|
||||
guint n_fpoints = 0;
|
||||
GdkRGBA color;
|
||||
|
||||
fpoints = point_cache_get_points (priv->cache, line_info->id, &n_fpoints);
|
||||
|
||||
if (n_fpoints > 0)
|
||||
{
|
||||
gdouble last_x = 0;
|
||||
gdouble last_y = 0;
|
||||
guint p;
|
||||
|
||||
points = g_new0 (SysprofVisualizerAbsolutePoint, n_fpoints);
|
||||
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
|
||||
(const SysprofVisualizerRelativePoint *)fpoints,
|
||||
n_fpoints,
|
||||
points,
|
||||
n_fpoints);
|
||||
|
||||
for (p = 0; p < n_fpoints; p++)
|
||||
{
|
||||
if (points[p].x >= clip.x)
|
||||
break;
|
||||
}
|
||||
|
||||
if (p >= n_fpoints)
|
||||
goto cleanup;
|
||||
|
||||
if (p > 0)
|
||||
p--;
|
||||
|
||||
last_x = points[p].x;
|
||||
last_y = points[p].y;
|
||||
|
||||
if (line_info->fill)
|
||||
{
|
||||
cairo_move_to (cr, last_x, alloc.height);
|
||||
cairo_line_to (cr, last_x, last_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_move_to (cr, last_x, last_y);
|
||||
}
|
||||
|
||||
for (guint i = p + 1; i < n_fpoints; i++)
|
||||
{
|
||||
cairo_curve_to (cr,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
last_y,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
points[i].y,
|
||||
points[i].x,
|
||||
points[i].y);
|
||||
|
||||
last_x = points[i].x;
|
||||
last_y = points[i].y;
|
||||
|
||||
if (points[i].x > clip.x + clip.width)
|
||||
break;
|
||||
}
|
||||
|
||||
if (line_info->fill)
|
||||
{
|
||||
cairo_line_to (cr, last_x, alloc.height);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
|
||||
cairo_set_line_width (cr, line_info->line_width);
|
||||
|
||||
if (line_info->use_dash)
|
||||
cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
|
||||
|
||||
if (line_info->fill)
|
||||
{
|
||||
gdk_cairo_set_source_rgba (cr, &line_info->background);
|
||||
cairo_fill_preserve (cr);
|
||||
}
|
||||
|
||||
if (line_info->use_default_style)
|
||||
color = foreground;
|
||||
else
|
||||
color = line_info->foreground;
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!attrs)
|
||||
{
|
||||
attrs = pango_attr_list_new ();
|
||||
pango_attr_list_insert (attrs, pango_attr_scale_new (0.666));
|
||||
}
|
||||
|
||||
if (priv->y_upper != 100.0)
|
||||
{
|
||||
if (priv->units)
|
||||
upper = g_strdup_printf ("%lg %s", priv->y_upper, priv->units);
|
||||
else
|
||||
upper = g_strdup_printf ("%lg", priv->y_upper);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, upper);
|
||||
pango_layout_set_attributes (layout, attrs);
|
||||
cairo_move_to (cr, 2, 2);
|
||||
foreground.alpha *= 0.5;
|
||||
gdk_cairo_set_source_rgba (cr, &foreground);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
g_clear_object (&layout);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_load_data_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofLineVisualizer *self = (SysprofLineVisualizer *)object;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(PointCache) cache = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
cache = sysprof_line_visualizer_load_data_finish (self, result, &error);
|
||||
|
||||
if (cache == NULL)
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->cache, point_cache_unref);
|
||||
priv->cache = g_steal_pointer (&cache);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_line_visualizer_do_reload (gpointer data)
|
||||
{
|
||||
SysprofLineVisualizer *self = data;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
priv->queued_load = 0;
|
||||
|
||||
if (priv->reader != NULL)
|
||||
{
|
||||
sysprof_line_visualizer_load_data_async (self,
|
||||
NULL,
|
||||
sysprof_line_visualizer_load_data_cb,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_queue_reload (SysprofLineVisualizer *self)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
if (priv->queued_load == 0)
|
||||
priv->queued_load = g_idle_add_full (G_PRIORITY_LOW,
|
||||
sysprof_line_visualizer_do_reload,
|
||||
self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_set_reader (SysprofVisualizer *row,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofLineVisualizer *self = (SysprofLineVisualizer *)row;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
if (priv->reader != reader)
|
||||
{
|
||||
if (priv->reader != NULL)
|
||||
{
|
||||
sysprof_capture_reader_unref (priv->reader);
|
||||
priv->reader = NULL;
|
||||
}
|
||||
|
||||
if (reader != NULL)
|
||||
priv->reader = sysprof_capture_reader_ref (reader);
|
||||
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofLineVisualizer *self = (SysprofLineVisualizer *)object;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->units, g_free);
|
||||
g_clear_pointer (&priv->lines, g_array_unref);
|
||||
g_clear_pointer (&priv->cache, point_cache_unref);
|
||||
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
|
||||
|
||||
g_clear_handle_id (&priv->queued_load, g_source_remove);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_line_visualizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofLineVisualizer *self = SYSPROF_LINE_VISUALIZER (object);
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_Y_LOWER:
|
||||
g_value_set_double (value, priv->y_lower);
|
||||
break;
|
||||
|
||||
case PROP_Y_UPPER:
|
||||
g_value_set_double (value, priv->y_upper);
|
||||
break;
|
||||
|
||||
case PROP_UNITS:
|
||||
g_value_set_string (value, priv->units);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofLineVisualizer *self = SYSPROF_LINE_VISUALIZER (object);
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_Y_LOWER:
|
||||
priv->y_lower = g_value_get_double (value);
|
||||
priv->y_lower_set = TRUE;
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_Y_UPPER:
|
||||
priv->y_upper = g_value_get_double (value);
|
||||
priv->y_upper_set = TRUE;
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_UNITS:
|
||||
g_free (priv->units);
|
||||
priv->units = g_value_dup_string (value);
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_class_init (SysprofLineVisualizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_line_visualizer_finalize;
|
||||
object_class->get_property = sysprof_line_visualizer_get_property;
|
||||
object_class->set_property = sysprof_line_visualizer_set_property;
|
||||
|
||||
widget_class->snapshot = sysprof_line_visualizer_snapshot;
|
||||
|
||||
visualizer_class->set_reader = sysprof_line_visualizer_set_reader;
|
||||
|
||||
properties [PROP_Y_LOWER] =
|
||||
g_param_spec_double ("y-lower",
|
||||
"Y Lower",
|
||||
"The lowest Y value for the visualizer",
|
||||
-G_MAXDOUBLE,
|
||||
G_MAXDOUBLE,
|
||||
0.0,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_Y_UPPER] =
|
||||
g_param_spec_double ("y-upper",
|
||||
"Y Upper",
|
||||
"The highest Y value for the visualizer",
|
||||
-G_MAXDOUBLE,
|
||||
G_MAXDOUBLE,
|
||||
100.0,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_UNITS] =
|
||||
g_param_spec_string ("units",
|
||||
"Units",
|
||||
"The format for units (mHz, Watts, etc)",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_init (SysprofLineVisualizer *self)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
priv->lines = g_array_new (FALSE, FALSE, sizeof (LineInfo));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_add_counter (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
LineInfo line_info = { 0 };
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
g_assert (priv->lines != NULL);
|
||||
|
||||
line_info.id = counter_id;
|
||||
line_info.line_width = 1.0;
|
||||
line_info.type = SYSPROF_CAPTURE_COUNTER_DOUBLE;
|
||||
|
||||
if (color != NULL)
|
||||
{
|
||||
line_info.foreground = *color;
|
||||
line_info.use_default_style = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_rgba_parse (&line_info.foreground, "#000");
|
||||
line_info.use_default_style = TRUE;
|
||||
}
|
||||
|
||||
g_array_append_val (priv->lines, line_info);
|
||||
|
||||
if (SYSPROF_LINE_VISUALIZER_GET_CLASS (self)->counter_added)
|
||||
SYSPROF_LINE_VISUALIZER_GET_CLASS (self)->counter_added (self, counter_id);
|
||||
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_clear (SysprofLineVisualizer *self)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
if (priv->lines->len > 0)
|
||||
g_array_remove_range (priv->lines, 0, priv->lines->len);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
contains_id (GArray *ar,
|
||||
guint id)
|
||||
{
|
||||
for (guint i = 0; i < ar->len; i++)
|
||||
{
|
||||
const LineInfo *info = &g_array_index (ar, LineInfo, i);
|
||||
|
||||
if (info->id == id)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline guint8
|
||||
counter_type (LoadData *load,
|
||||
guint counter_id)
|
||||
{
|
||||
for (guint i = 0; i < load->lines->len; i++)
|
||||
{
|
||||
const LineInfo *info = &g_array_index (load->lines, LineInfo, i);
|
||||
|
||||
if (info->id == counter_id)
|
||||
return info->type;
|
||||
}
|
||||
|
||||
return SYSPROF_CAPTURE_COUNTER_DOUBLE;
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
calc_x (gint64 lower,
|
||||
gint64 upper,
|
||||
gint64 value)
|
||||
{
|
||||
return (gdouble)(value - lower) / (gdouble)(upper - lower);
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
calc_y_double (gdouble lower,
|
||||
gdouble upper,
|
||||
gdouble value)
|
||||
{
|
||||
return (value - lower) / (upper - lower);
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
calc_y_int64 (gint64 lower,
|
||||
gint64 upper,
|
||||
gint64 value)
|
||||
{
|
||||
return (gdouble)(value - lower) / (gdouble)(upper - lower);
|
||||
}
|
||||
|
||||
static bool
|
||||
sysprof_line_visualizer_load_data_frame_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
LoadData *load = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (load != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
const SysprofCaptureCounterSet *set = (SysprofCaptureCounterSet *)frame;
|
||||
gdouble x = calc_x (load->begin_time, load->end_time, frame->time);
|
||||
|
||||
for (guint i = 0; i < set->n_values; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *group = &set->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (group->ids); j++)
|
||||
{
|
||||
guint counter_id = group->ids[j];
|
||||
|
||||
if (counter_id != 0 && contains_id (load->lines, counter_id))
|
||||
{
|
||||
gdouble y;
|
||||
|
||||
if (counter_type (load, counter_id) == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
y = calc_y_double (load->y_lower, load->y_upper, group->values[j].vdbl);
|
||||
else
|
||||
y = calc_y_int64 (load->y_lower, load->y_upper, group->values[j].v64);
|
||||
|
||||
point_cache_add_point_to_set (load->cache, counter_id, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
sysprof_line_visualizer_load_data_range_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
LoadData *load = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (load != NULL);
|
||||
g_assert (load->y_upper_set == FALSE ||
|
||||
load->y_lower_set == FALSE);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
|
||||
{
|
||||
const SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &def->counters[i];
|
||||
|
||||
for (guint j = 0; j < load->lines->len; j++)
|
||||
{
|
||||
LineInfo *info = &g_array_index (load->lines, LineInfo, j);
|
||||
|
||||
if (info->id == ctr->id)
|
||||
{
|
||||
info->type = ctr->type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
const SysprofCaptureCounterSet *set = (SysprofCaptureCounterSet *)frame;
|
||||
|
||||
for (guint i = 0; i < set->n_values; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *group = &set->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (group->ids); j++)
|
||||
{
|
||||
guint counter_id = group->ids[j];
|
||||
|
||||
if (counter_id != 0 && contains_id (load->lines, counter_id))
|
||||
{
|
||||
gdouble y;
|
||||
|
||||
if (counter_type (load, counter_id) == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
y = group->values[j].vdbl;
|
||||
else
|
||||
y = group->values[j].v64;
|
||||
|
||||
if (!load->y_upper_set)
|
||||
load->y_upper = MAX (load->y_upper, y);
|
||||
|
||||
if (!load->y_lower_set)
|
||||
load->y_lower = MIN (load->y_lower, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_load_data_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
LoadData *load = task_data;
|
||||
g_autoptr(GArray) counter_ids = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (source_object));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counter_ids = g_array_new (FALSE, FALSE, sizeof (guint));
|
||||
|
||||
for (guint i = 0; i < load->lines->len; i++)
|
||||
{
|
||||
const LineInfo *line_info = &g_array_index (load->lines, LineInfo, i);
|
||||
g_array_append_val (counter_ids, line_info->id);
|
||||
}
|
||||
|
||||
sysprof_capture_cursor_add_condition (load->cursor,
|
||||
sysprof_capture_condition_new_where_counter_in (counter_ids->len,
|
||||
(guint *)(gpointer)counter_ids->data));
|
||||
|
||||
/* If y boundaries are not set, we need to discover them by scaning the data. */
|
||||
if (!load->y_lower_set || !load->y_upper_set)
|
||||
{
|
||||
sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_load_data_range_cb, load);
|
||||
sysprof_capture_cursor_reset (load->cursor);
|
||||
|
||||
/* Add extra boundary for some space above the graph line */
|
||||
if (G_MAXDOUBLE - load->y_upper > (load->y_upper * .25))
|
||||
load->y_upper = load->y_upper + ((load->y_upper - load->y_lower) * .25);
|
||||
}
|
||||
|
||||
sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_load_data_frame_cb, load);
|
||||
g_task_return_pointer (task, g_steal_pointer (&load->cache), (GDestroyNotify)point_cache_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_load_data_async (SysprofLineVisualizer *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
g_autoptr(GTask) task = NULL;
|
||||
LoadData *load;
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_priority (task, G_PRIORITY_LOW);
|
||||
g_task_set_source_tag (task, sysprof_line_visualizer_load_data_async);
|
||||
|
||||
if (priv->reader == NULL)
|
||||
{
|
||||
g_task_return_new_error (task,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"No data loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
load = g_slice_new0 (LoadData);
|
||||
load->cache = point_cache_new ();
|
||||
load->y_lower = priv->y_lower_set ? priv->y_lower : G_MAXDOUBLE;
|
||||
load->y_upper = priv->y_upper_set ? priv->y_upper : -G_MAXDOUBLE;
|
||||
load->y_lower_set = priv->y_lower_set;
|
||||
load->y_upper_set = priv->y_upper_set;
|
||||
load->begin_time = sysprof_capture_reader_get_start_time (priv->reader);
|
||||
load->end_time = sysprof_capture_reader_get_end_time (priv->reader);
|
||||
load->cursor = sysprof_capture_cursor_new (priv->reader);
|
||||
load->lines = copy_array (priv->lines);
|
||||
|
||||
for (guint i = 0; i < load->lines->len; i++)
|
||||
{
|
||||
const LineInfo *line_info = &g_array_index (load->lines, LineInfo, i);
|
||||
|
||||
point_cache_add_set (load->cache, line_info->id);
|
||||
}
|
||||
|
||||
g_task_set_task_data (task, load, load_data_free);
|
||||
g_task_run_in_thread (task, sysprof_line_visualizer_load_data_worker);
|
||||
}
|
||||
|
||||
static PointCache *
|
||||
sysprof_line_visualizer_load_data_finish (SysprofLineVisualizer *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
LoadData *state;
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
state = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if (!priv->y_lower_set && priv->y_lower != state->y_lower)
|
||||
{
|
||||
priv->y_lower = state->y_lower;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_Y_LOWER]);
|
||||
}
|
||||
|
||||
if (!priv->y_upper_set && priv->y_upper != state->y_upper)
|
||||
{
|
||||
priv->y_upper = state->y_upper;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_Y_UPPER]);
|
||||
}
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (result), error);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_set_line_width (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
gdouble width)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
for (guint i = 0; i < priv->lines->len; i++)
|
||||
{
|
||||
LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
|
||||
|
||||
if (info->id == counter_id)
|
||||
{
|
||||
info->line_width = width;
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_set_fill (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
for (guint i = 0; i < priv->lines->len; i++)
|
||||
{
|
||||
LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
|
||||
|
||||
if (info->id == counter_id)
|
||||
{
|
||||
info->fill = !!color;
|
||||
if (color != NULL)
|
||||
info->background = *color;
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_set_dash (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
gboolean use_dash)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
for (guint i = 0; i < priv->lines->len; i++)
|
||||
{
|
||||
LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
|
||||
|
||||
if (info->id == counter_id)
|
||||
{
|
||||
info->use_dash = !!use_dash;
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/* sysprof-line-visualizer.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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 "sysprof-visualizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_LINE_VISUALIZER (sysprof_line_visualizer_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofLineVisualizer, sysprof_line_visualizer, SYSPROF, LINE_VISUALIZER, SysprofVisualizer)
|
||||
|
||||
struct _SysprofLineVisualizerClass
|
||||
{
|
||||
SysprofVisualizerClass parent_class;
|
||||
|
||||
void (*counter_added) (SysprofLineVisualizer *self,
|
||||
guint counter_id);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
GtkWidget *sysprof_line_visualizer_new (void);
|
||||
void sysprof_line_visualizer_clear (SysprofLineVisualizer *self);
|
||||
void sysprof_line_visualizer_add_counter (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
const GdkRGBA *color);
|
||||
void sysprof_line_visualizer_set_line_width (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
gdouble width);
|
||||
void sysprof_line_visualizer_set_fill (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
const GdkRGBA *color);
|
||||
void sysprof_line_visualizer_set_dash (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
gboolean use_dash);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,422 +0,0 @@
|
||||
/* sysprof-log-model.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-log-model"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-log-model.h"
|
||||
|
||||
struct _SysprofLogModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
GStringChunk *chunks;
|
||||
GArray *items;
|
||||
gint64 begin_time;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 time;
|
||||
const gchar *domain;
|
||||
const gchar *message;
|
||||
guint16 severity;
|
||||
} Item;
|
||||
|
||||
static gint
|
||||
sysprof_log_model_get_n_columns (GtkTreeModel *model)
|
||||
{
|
||||
return SYSPROF_LOG_MODEL_COLUMN_LAST;
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_log_model_get_column_type (GtkTreeModel *model,
|
||||
gint column)
|
||||
{
|
||||
switch (column)
|
||||
{
|
||||
case SYSPROF_LOG_MODEL_COLUMN_TIME:
|
||||
return G_TYPE_INT64;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_SEVERITY:
|
||||
case SYSPROF_LOG_MODEL_COLUMN_DOMAIN:
|
||||
case SYSPROF_LOG_MODEL_COLUMN_MESSAGE:
|
||||
case SYSPROF_LOG_MODEL_COLUMN_TIME_STRING:
|
||||
return G_TYPE_STRING;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkTreePath *
|
||||
sysprof_log_model_get_path (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (model));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
off = GPOINTER_TO_INT (iter->user_data);
|
||||
|
||||
return gtk_tree_path_new_from_indices (off, -1);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_log_model_get_iter (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreePath *path)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
g_assert (path != NULL);
|
||||
|
||||
memset (iter, 0, sizeof *iter);
|
||||
|
||||
if (gtk_tree_path_get_depth (path) != 1)
|
||||
return FALSE;
|
||||
|
||||
off = gtk_tree_path_get_indices (path)[0];
|
||||
iter->user_data = GINT_TO_POINTER (off);
|
||||
|
||||
return off >= 0 && off < self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_log_model_iter_next (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
off = GPOINTER_TO_INT (iter->user_data);
|
||||
off++;
|
||||
iter->user_data = GINT_TO_POINTER (off);
|
||||
|
||||
return off < self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_log_model_iter_nth_child (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreeIter *parent,
|
||||
gint n)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
if (parent != NULL)
|
||||
return FALSE;
|
||||
|
||||
iter->user_data = GINT_TO_POINTER (n);
|
||||
|
||||
return n < self->items->len;
|
||||
}
|
||||
|
||||
static gint
|
||||
sysprof_log_model_iter_n_children (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
|
||||
return iter ? 0 : self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_log_model_iter_has_child (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkTreeModelFlags
|
||||
sysprof_log_model_get_flags (GtkTreeModel *model)
|
||||
{
|
||||
return GTK_TREE_MODEL_LIST_ONLY;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_get_value (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gint column,
|
||||
GValue *value)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
const Item *item;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
g_assert (column < SYSPROF_LOG_MODEL_COLUMN_LAST);
|
||||
|
||||
item = &g_array_index (self->items, Item, GPOINTER_TO_INT (iter->user_data));
|
||||
|
||||
switch (column)
|
||||
{
|
||||
case SYSPROF_LOG_MODEL_COLUMN_TIME_STRING:
|
||||
{
|
||||
gint64 offset = item->time - self->begin_time;
|
||||
gint min = offset / SYSPROF_NSEC_PER_SEC / 60L;
|
||||
gint seconds = ((offset - (min * SYSPROF_NSEC_PER_SEC)) / SYSPROF_NSEC_PER_SEC) % 60;
|
||||
gint msec = (offset % SYSPROF_NSEC_PER_SEC) / (SYSPROF_NSEC_PER_SEC / 1000L);
|
||||
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_take_string (value,
|
||||
g_strdup_printf ("%02d:%02d.%03d", min, seconds, msec));
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_TIME:
|
||||
g_value_init (value, G_TYPE_INT64);
|
||||
g_value_set_int64 (value, item->time);
|
||||
break;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_SEVERITY:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
switch (item->severity)
|
||||
{
|
||||
case G_LOG_LEVEL_MESSAGE:
|
||||
g_value_set_static_string (value, _("Message"));
|
||||
break;
|
||||
case G_LOG_LEVEL_INFO:
|
||||
g_value_set_static_string (value, _("Info"));
|
||||
break;
|
||||
case G_LOG_LEVEL_CRITICAL:
|
||||
g_value_set_static_string (value, _("Critical"));
|
||||
break;
|
||||
case G_LOG_LEVEL_ERROR:
|
||||
g_value_set_static_string (value, _("Error"));
|
||||
break;
|
||||
case G_LOG_LEVEL_DEBUG:
|
||||
g_value_set_static_string (value, _("Debug"));
|
||||
break;
|
||||
case G_LOG_LEVEL_WARNING:
|
||||
g_value_set_static_string (value, _("Warning"));
|
||||
break;
|
||||
default:
|
||||
g_value_set_static_string (value, "");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_DOMAIN:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_set_string (value, item->domain);
|
||||
break;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_MESSAGE:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_set_string (value, item->message);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tree_model_iface_init (GtkTreeModelIface *iface)
|
||||
{
|
||||
iface->get_n_columns = sysprof_log_model_get_n_columns;
|
||||
iface->get_column_type = sysprof_log_model_get_column_type;
|
||||
iface->get_iter = sysprof_log_model_get_iter;
|
||||
iface->get_path = sysprof_log_model_get_path;
|
||||
iface->iter_next = sysprof_log_model_iter_next;
|
||||
iface->iter_n_children = sysprof_log_model_iter_n_children;
|
||||
iface->iter_nth_child = sysprof_log_model_iter_nth_child;
|
||||
iface->iter_has_child = sysprof_log_model_iter_has_child;
|
||||
iface->get_flags = sysprof_log_model_get_flags;
|
||||
iface->get_value = sysprof_log_model_get_value;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (SysprofLogModel, sysprof_log_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, tree_model_iface_init))
|
||||
|
||||
static void
|
||||
sysprof_log_model_finalize (GObject *object)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)object;
|
||||
|
||||
g_clear_pointer (&self->items, g_array_unref);
|
||||
g_clear_pointer (&self->chunks, g_string_chunk_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_log_model_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_class_init (SysprofLogModelClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_log_model_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_init (SysprofLogModel *self)
|
||||
{
|
||||
self->chunks = g_string_chunk_new (4096*16);
|
||||
self->items = g_array_new (FALSE, FALSE, sizeof (Item));
|
||||
}
|
||||
|
||||
static bool
|
||||
cursor_foreach_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofLogModel *self = user_data;
|
||||
SysprofCaptureLog *log = (SysprofCaptureLog *)frame;
|
||||
Item item;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_LOG);
|
||||
|
||||
item.time = frame->time;
|
||||
item.severity = log->severity;
|
||||
item.domain = g_string_chunk_insert_const (self->chunks, log->domain);
|
||||
item.message = g_string_chunk_insert_const (self->chunks, log->message);
|
||||
|
||||
g_array_append_val (self->items, item);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
item_compare (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const Item *ia = a;
|
||||
const Item *ib = b;
|
||||
|
||||
if (ia->time < ib->time)
|
||||
return -1;
|
||||
else if (ia->time > ib->time)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_new_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
g_autoptr(SysprofLogModel) self = NULL;
|
||||
SysprofCaptureCursor *cursor = task_data;
|
||||
SysprofCaptureReader *reader;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_LOG_MODEL, NULL);
|
||||
|
||||
reader = sysprof_capture_cursor_get_reader (cursor);
|
||||
self->begin_time = sysprof_capture_reader_get_start_time (reader);
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, cursor_foreach_cb, self);
|
||||
g_array_sort (self->items, item_compare);
|
||||
|
||||
g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_selection_foreach_cb (SysprofSelection *selection,
|
||||
gint64 begin,
|
||||
gint64 end,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCondition **condition = user_data;
|
||||
SysprofCaptureCondition *c;
|
||||
|
||||
g_assert (SYSPROF_IS_SELECTION (selection));
|
||||
g_assert (condition != NULL);
|
||||
|
||||
c = sysprof_capture_condition_new_where_time_between (begin, end);
|
||||
|
||||
if (*condition != NULL)
|
||||
*condition = sysprof_capture_condition_new_or (g_steal_pointer (&c),
|
||||
g_steal_pointer (condition));
|
||||
else
|
||||
*condition = g_steal_pointer (&c);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_log_model_new_async (SysprofCaptureReader *reader,
|
||||
SysprofSelection *selection,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = {
|
||||
SYSPROF_CAPTURE_FRAME_LOG,
|
||||
};
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
SysprofCaptureCondition *c;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_return_if_fail (reader != NULL);
|
||||
g_return_if_fail (!selection || SYSPROF_IS_SELECTION (selection));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
|
||||
if (selection)
|
||||
{
|
||||
SysprofCaptureCondition *condition = NULL;
|
||||
|
||||
sysprof_selection_foreach (selection,
|
||||
sysprof_log_model_selection_foreach_cb,
|
||||
&condition);
|
||||
if (condition)
|
||||
c = sysprof_capture_condition_new_and (c, g_steal_pointer (&condition));
|
||||
}
|
||||
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&c));
|
||||
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_log_model_new_async);
|
||||
g_task_set_task_data (task,
|
||||
g_steal_pointer (&cursor),
|
||||
(GDestroyNotify) sysprof_capture_cursor_unref);
|
||||
g_task_run_in_thread (task, sysprof_log_model_new_worker);
|
||||
}
|
||||
|
||||
SysprofLogModel *
|
||||
sysprof_log_model_new_finish (GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_TASK (result), NULL);
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (result), error);
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
/* sysprof-log-model.h
|
||||
*
|
||||
* Copyright 2019 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 <sysprof.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SYSPROF_LOG_MODEL_COLUMN_TIME,
|
||||
SYSPROF_LOG_MODEL_COLUMN_SEVERITY,
|
||||
SYSPROF_LOG_MODEL_COLUMN_DOMAIN,
|
||||
SYSPROF_LOG_MODEL_COLUMN_MESSAGE,
|
||||
SYSPROF_LOG_MODEL_COLUMN_TIME_STRING,
|
||||
SYSPROF_LOG_MODEL_COLUMN_LAST
|
||||
} SysprofLogModelColumn;
|
||||
|
||||
#define SYSPROF_TYPE_LOG_MODEL (sysprof_log_model_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofLogModel, sysprof_log_model, SYSPROF, LOG_MODEL, GObject)
|
||||
|
||||
void sysprof_log_model_new_async (SysprofCaptureReader *reader,
|
||||
SysprofSelection *selection,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SysprofLogModel *sysprof_log_model_new_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user