Innteresting. It seems that the `output` collection is much more
reliable as a source of truth about which monitors and screens are actually in use. Each one comes with its own collection of `crtc`, but you can just skip the ones that return `null`, giving you a reliable list of the "active and visible" screens that the user is currently looking at. Excellent! This means that I'm one step closer to having a viable solution! I also discovered the [xcb_util](https://xcb.freedesktop.org/XcbUtil/) library of helpful utilities has a function called `xcb_aux_get_screen` for getting the root screen because everyone was weirded out by that list traversal algorithm. The source code to [xedgewarp](https://github.com/Airblader/xedgewarp) was invaluable in revealing these secrets to me. So far this little toy compiles down to only 35KB, and that includes using `std::cout` and `std::vector`! I wonder how big the Rust version will be. Yeah, yeah, I know, it cheats by having lots of itself hidden in the kernel. Next up: Actually knowing what the rotation status is.
This commit is contained in:
parent
8a700005c3
commit
2cd9b268a8
|
@ -0,0 +1,178 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
AlignConsecutiveMacros: None
|
||||||
|
AlignConsecutiveAssignments: None
|
||||||
|
AlignConsecutiveBitFields: None
|
||||||
|
AlignConsecutiveDeclarations: None
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeConceptDeclarations: true
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 100
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DeriveLineEnding: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IfMacros:
|
||||||
|
- KJ_IF_MAYBE
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentExternBlock: AfterExternBlock
|
||||||
|
IndentRequires: false
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
PointerAlignment: Left
|
||||||
|
PPIndentWidth: -1
|
||||||
|
ReferenceAlignment: Pointer
|
||||||
|
ReflowComments: true
|
||||||
|
ShortNamespaceLines: 1
|
||||||
|
SortIncludes: CaseSensitive
|
||||||
|
SortJavaStaticImport: Before
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: Never
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
Standard: Latest
|
||||||
|
StatementAttributeLikeMacros:
|
||||||
|
- Q_EMIT
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 8
|
||||||
|
UseCRLF: false
|
||||||
|
UseTab: Never
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- STRINGIZE
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
...
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -12,3 +12,6 @@ build/xrandr: build/Makefile src/xrandr.cpp CMakeLists.txt
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr build
|
rm -fr build
|
||||||
|
|
||||||
|
run: build/xrandr
|
||||||
|
./build/xrandr
|
||||||
|
|
|
@ -19,7 +19,10 @@ obviously X Windows.
|
||||||
|
|
||||||
In progress.
|
In progress.
|
||||||
|
|
||||||
**DETAILS:**
|
DETAILS:
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
|
||||||
|
|
||||||
**BUILDING:**
|
**BUILDING:**
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
Resources used in the production of this program:
|
||||||
|
|
||||||
|
- [The XCB Reference from FreeDesktop](https://xcb.freedesktop.org/manual/index.html)
|
||||||
|
- [The Xorg Basic Programming with the XCB
|
||||||
|
Library](https://www.x.org/releases/X11R7.6/doc/libxcb/tutorial/index.html),
|
||||||
|
- [The KDE Source Code for
|
||||||
|
XCBWrapper](https://github.com/KDE/libkscreen/tree/master/backends),
|
||||||
|
- [xedgewarp](https://github.com/Airblader/xedgewarp)
|
||||||
|
[Vlad Zahorodnii](https://github.com/zzag) et. al., ongoing.
|
||||||
|
- [C++ in a
|
||||||
|
Nutshell](https://www.oreilly.com/library/view/c-in-a/059600298X/)
|
||||||
|
Ray Lischner, O'Reilly Publishing, 2003
|
||||||
|
|
||||||
|
The sheer variety of sources I needed to cobble together an
|
||||||
|
understanding how the XCB library works is an example of what teachers
|
||||||
|
call [extrinsic
|
||||||
|
load](https://betterhumans.pub/skyrocket-your-learning-top-3-studying-techniques-based-on-cognitive-load-theory-1641b5e56508),
|
||||||
|
an unnecessary extra load on learning because the documentation is
|
||||||
|
poorly organized and lacks instruction. *Basic Programming with XCB*
|
||||||
|
is a
|
||||||
|
*[tutorial](https://www.writethedocs.org/videos/eu/2017/the-four-kinds-of-documentation-and-why-you-need-to-understand-what-they-are-daniele-procida/)*
|
||||||
|
oriented toward commonplace tasks, but peters out before getting to an
|
||||||
|
XCB extensions such as RandR. The reference is a *reference*; it
|
||||||
|
doesn't help you understand how to use the library. `XCBWrapper` is
|
||||||
|
an excellent example of how to use XCB, but it uses some fairly
|
||||||
|
high-level C++ to accomplish all that it does, and untangling the
|
||||||
|
relationship between the wrapper template, the macro that does wrapper
|
||||||
|
declarations, and the XCB Reference; once you find the insight that
|
||||||
|
XCB's declarations are all derived from a massive XML file, you can
|
||||||
|
start to understand that XCBWrapper exploits the patterns produced by
|
||||||
|
the derivative file, but it requires insight and effort that's
|
||||||
|
unrelated to understanding XCB in the first place.
|
||||||
|
|
||||||
|
This project does show the usual trajectory of one of my learning
|
||||||
|
exercises, especially since I'm fond of delving in places where no man
|
||||||
|
has documented before. I've dumped a ton of stuff into my brain and
|
||||||
|
now it's all starting to make sense. I also note that I'm doing
|
||||||
|
_better_ than a lot of the open-source examples, in that I'm batching
|
||||||
|
many of my requests before processing them. I'm not batching storing
|
||||||
|
the replies yet, but I don't see why that couldn't happen.
|
|
@ -0,0 +1,8 @@
|
||||||
|
- A Display has Screens
|
||||||
|
- A Screen has Monitors & Windows
|
||||||
|
- The root Screen is accessed by traversing to the head of the list of
|
||||||
|
screens using an interator.
|
||||||
|
- The root screen's root window is used as the parameter for
|
||||||
|
'get_screen_resources'.
|
||||||
|
- The screen_resources object is contains 'screen_resources_crtcs',
|
||||||
|
which you again get via an iterator. These are cookies.
|
156
src/xrandr.cpp
156
src/xrandr.cpp
|
@ -1,14 +1,154 @@
|
||||||
|
#include "xcb/randr.h"
|
||||||
|
#include "xcb/xcb.h"
|
||||||
|
#include "xcb/xcb_aux.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <xcb/xcb.h>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
xcb_randr_get_screen_resources_reply_t* get_screen_resources(xcb_connection_t* connection,
|
||||||
|
xcb_window_t rootWindow) {
|
||||||
|
return xcb_randr_get_screen_resources_reply(
|
||||||
|
connection, xcb_randr_get_screen_resources(connection, rootWindow), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<xcb_randr_crtc_t> get_crtc_cookies(xcb_randr_get_screen_resources_reply_t* resources) {
|
||||||
|
std::vector<xcb_randr_crtc_t> reply;
|
||||||
|
xcb_randr_crtc_t* crtcs = xcb_randr_get_screen_resources_crtcs(resources);
|
||||||
|
const int crtcsCount = xcb_randr_get_screen_resources_crtcs_length(resources);
|
||||||
|
for (int i = 0; i < crtcsCount; ++i) {
|
||||||
|
reply.push_back(crtcs[i]);
|
||||||
|
}
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_one_crtc(xcb_randr_get_crtc_info_reply_t* crtc) {
|
||||||
|
std::cout << "(x: " << crtc->x << ", y: " << crtc->y << ") (width: " << crtc->width
|
||||||
|
<< ", height: " << crtc->height << ") status:" << unsigned(crtc->status) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_crtc_info(xcb_connection_t* connection, std::vector<xcb_randr_crtc_t>& crtc_cs) {
|
||||||
|
std::vector<xcb_randr_get_crtc_info_cookie_t> cookies;
|
||||||
|
xcb_generic_error_t* error = nullptr;
|
||||||
|
for (const auto& crtc : crtc_cs) {
|
||||||
|
cookies.push_back(xcb_randr_get_crtc_info(connection, crtc, XCB_CURRENT_TIME));
|
||||||
|
}
|
||||||
|
for (const auto& cookie : cookies) {
|
||||||
|
xcb_randr_get_crtc_info_reply_t* reply =
|
||||||
|
xcb_randr_get_crtc_info_reply(connection, cookie, &error);
|
||||||
|
if (error) {
|
||||||
|
free(error);
|
||||||
|
} else {
|
||||||
|
display_one_crtc(reply);
|
||||||
|
free(reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_one_output(xcb_connection_t* connection, xcb_randr_get_output_info_reply_t* output,
|
||||||
|
xcb_timestamp_t timestamp) {
|
||||||
|
xcb_randr_get_crtc_info_reply_t* crtc = xcb_randr_get_crtc_info_reply(
|
||||||
|
connection, xcb_randr_get_crtc_info(connection, output->crtc, timestamp), NULL);
|
||||||
|
if (!crtc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
display_one_crtc(crtc);
|
||||||
|
free(crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_outputs(xcb_connection_t* connection,
|
||||||
|
xcb_randr_get_screen_resources_reply_t* resources, xcb_timestamp_t timestamp) {
|
||||||
|
std::vector<xcb_randr_get_output_info_cookie_t> cookies;
|
||||||
|
xcb_generic_error_t* error = nullptr;
|
||||||
|
|
||||||
|
int len = xcb_randr_get_screen_resources_outputs_length(resources);
|
||||||
|
xcb_randr_output_t* randr_outputs = xcb_randr_get_screen_resources_outputs(resources);
|
||||||
|
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
cookies.push_back(xcb_randr_get_output_info(connection, randr_outputs[i], timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& cookie : cookies) {
|
||||||
|
xcb_randr_get_output_info_reply_t* reply =
|
||||||
|
xcb_randr_get_output_info_reply(connection, cookie, &error);
|
||||||
|
if (error) {
|
||||||
|
free(error);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
display_one_output(connection, reply, timestamp);
|
||||||
|
free(reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lesson of the day: All _reply_t* objects must be freed.
|
||||||
|
//
|
||||||
|
// xcb_randr_rotation_t)
|
||||||
|
// }
|
||||||
|
// get_rotation(xcb_connection_t* connection, xcb_randr_crtc_t crtc) {
|
||||||
|
// xcb_generic_error_t* error = nullptr;
|
||||||
|
// xcb_randr_get_crtc_info_cookie_t cookie =
|
||||||
|
// xcb_randr_get_crtc_info(connection, crtc, XCB_CURRENT_TIME);
|
||||||
|
// xcb_randr_get_crtc_info_reply_t* reply =
|
||||||
|
// xcb_randr_get_crtc_info_reply(connection, cookie, &error);
|
||||||
|
// xcb_randr_rotation_t rotation =
|
||||||
|
// (xcb_randr_rotation_t)reply->rotation; free(reply); return rotation;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
xcb_randr_query_version_reply_t* getVersion(xcb_connection_t* connection) {
|
||||||
|
xcb_generic_error_t* error = nullptr;
|
||||||
|
xcb_randr_query_version_reply_t* version = xcb_randr_query_version_reply(
|
||||||
|
connection,
|
||||||
|
xcb_randr_query_version(connection, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION),
|
||||||
|
&error);
|
||||||
|
if (error) {
|
||||||
|
std::cout << "Error code:" << error->error_code << std::endl;
|
||||||
|
free(error);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!version) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_screen_info(int screen_id, xcb_screen_t* screen) {
|
||||||
|
std::cout << "Screen " << screen_id << " (" << screen->width_in_pixels << ", "
|
||||||
|
<< screen->height_in_pixels << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_randr_version(xcb_randr_query_version_reply_t* version) {
|
||||||
|
if (!version) {
|
||||||
|
std::cout << "Something went wrong retrieving the version number" << std::endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Server reports RandR version (" << version->major_version << "."
|
||||||
|
<< version->minor_version << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gives us a connection and a screen object.
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
xcb_connection_t *xConnection = xcb_connect(nullptr, nullptr);
|
int default_screen_id;
|
||||||
for (auto iter = xcb_setup_roots_iterator(xcb_get_setup(xConnection));
|
xcb_connection_t* xConnection = xcb_connect(nullptr, &default_screen_id);
|
||||||
iter.rem; xcb_screen_next(&iter)) {
|
|
||||||
xcb_screen_t *screen = iter.data;
|
auto screen = xcb_aux_get_screen(xConnection, default_screen_id);
|
||||||
std::cout << "Screen " << iter.index << " (" << screen->width_in_pixels
|
display_screen_info(default_screen_id, screen);
|
||||||
<< ", " << screen->height_in_pixels << ")" << std::endl;
|
|
||||||
}
|
xcb_randr_query_version_reply_t* version = getVersion(xConnection);
|
||||||
|
display_randr_version(version);
|
||||||
|
|
||||||
|
xcb_randr_get_screen_resources_reply_t* screen_resources =
|
||||||
|
get_screen_resources(xConnection, screen->root);
|
||||||
|
|
||||||
|
xcb_timestamp_t timestamp = screen_resources->config_timestamp;
|
||||||
|
|
||||||
|
display_outputs(xConnection, screen_resources, timestamp);
|
||||||
|
|
||||||
|
free(screen_resources);
|
||||||
xcb_disconnect(xConnection);
|
xcb_disconnect(xConnection);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,54 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
double get_time(void) {
|
||||||
|
struct timeval timev;
|
||||||
|
gettimeofday(&timev, NULL);
|
||||||
|
return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int count = 500;
|
||||||
|
xcb_atom_t* atoms = (xcb_atom_t*)malloc(count * sizeof(atoms));
|
||||||
|
xcb_intern_atom_cookie_t* cookies =
|
||||||
|
(xcb_intern_atom_cookie_t*)malloc(count * sizeof(xcb_intern_atom_cookie_t));
|
||||||
|
char** names;
|
||||||
|
double end, diff_x;
|
||||||
|
|
||||||
|
/* init names */
|
||||||
|
names = (char**)malloc(count * sizeof(char*));
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
char buf[100];
|
||||||
|
sprintf(buf, "NAME%d", i);
|
||||||
|
names[i] = strdup(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto start = get_time();
|
||||||
|
xcb_connection_t* connection = xcb_connect(NULL, NULL);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
cookies[i] = xcb_intern_atom(connection, 0, strlen(names[i]), names[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
xcb_intern_atom_reply_t* r = xcb_intern_atom_reply(connection, cookies[i], 0);
|
||||||
|
if (r) {
|
||||||
|
atoms[i] = r->atom;
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xcb_disconnect(connection);
|
||||||
|
end = get_time();
|
||||||
|
|
||||||
|
diff_x = end - start;
|
||||||
|
printf("XCB (good) use time : %f\n", diff_x);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
free(names[i]);
|
||||||
|
free(names);
|
||||||
|
free(atoms);
|
||||||
|
free(cookies);
|
||||||
|
return 0;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,44 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
double get_time(void) {
|
||||||
|
struct timeval timev;
|
||||||
|
gettimeofday(&timev, NULL);
|
||||||
|
return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int count = 500;
|
||||||
|
xcb_atom_t* atoms = (xcb_atom_t*)malloc(count * sizeof(atoms));
|
||||||
|
char** names;
|
||||||
|
double end, diff_x;
|
||||||
|
|
||||||
|
/* init names */
|
||||||
|
names = (char**)malloc(count * sizeof(char*));
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
char buf[100];
|
||||||
|
sprintf(buf, "NAME%d", i);
|
||||||
|
names[i] = strdup(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto start = get_time();
|
||||||
|
xcb_connection_t* connection = xcb_connect(NULL, NULL);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
atoms[i] = xcb_intern_atom_reply(
|
||||||
|
connection, xcb_intern_atom(connection, 0, strlen(names[i]), names[i]), NULL)
|
||||||
|
->atom;
|
||||||
|
}
|
||||||
|
xcb_disconnect(connection);
|
||||||
|
end = get_time();
|
||||||
|
|
||||||
|
diff_x = end - start;
|
||||||
|
printf("XCB (poor) use time : %f\n", diff_x);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
free(names[i]);
|
||||||
|
free(names);
|
||||||
|
return 0;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,43 @@
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
double get_time(void) {
|
||||||
|
struct timeval timev;
|
||||||
|
gettimeofday(&timev, NULL);
|
||||||
|
return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int count = 500;
|
||||||
|
Atom* atoms_x = (Atom*)malloc(count * sizeof(atoms_x));
|
||||||
|
char** names;
|
||||||
|
double end, diff_x;
|
||||||
|
|
||||||
|
/* init names */
|
||||||
|
names = (char**)malloc(count * sizeof(char*));
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
char buf[100];
|
||||||
|
sprintf(buf, "NAME%d", i);
|
||||||
|
names[i] = strdup(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto start = get_time();
|
||||||
|
auto disp = XOpenDisplay(getenv("DISPLAY"));
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
atoms_x[i] = XInternAtom(disp, names[i], 0);
|
||||||
|
end = get_time();
|
||||||
|
XCloseDisplay(disp);
|
||||||
|
|
||||||
|
diff_x = end - start;
|
||||||
|
printf("Xlib use time : %f\n", diff_x);
|
||||||
|
|
||||||
|
free(atoms_x);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
free(names[i]);
|
||||||
|
free(names);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue