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:
|
||||
rm -fr build
|
||||
|
||||
run: build/xrandr
|
||||
./build/xrandr
|
||||
|
|
|
@ -19,7 +19,10 @@ obviously X Windows.
|
|||
|
||||
In progress.
|
||||
|
||||
**DETAILS:**
|
||||
DETAILS:
|
||||
|
||||
**Notes:**
|
||||
|
||||
|
||||
**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 <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[]) {
|
||||
xcb_connection_t *xConnection = xcb_connect(nullptr, nullptr);
|
||||
for (auto iter = xcb_setup_roots_iterator(xcb_get_setup(xConnection));
|
||||
iter.rem; xcb_screen_next(&iter)) {
|
||||
xcb_screen_t *screen = iter.data;
|
||||
std::cout << "Screen " << iter.index << " (" << screen->width_in_pixels
|
||||
<< ", " << screen->height_in_pixels << ")" << std::endl;
|
||||
}
|
||||
int default_screen_id;
|
||||
xcb_connection_t* xConnection = xcb_connect(nullptr, &default_screen_id);
|
||||
|
||||
auto screen = xcb_aux_get_screen(xConnection, default_screen_id);
|
||||
display_screen_info(default_screen_id, screen);
|
||||
|
||||
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);
|
||||
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