• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tderandr
 

tderandr

  • tderandr
libtderandr.cpp
1/* libtderandr.cpp - class KRandr that makes it easy to use XRandr in KDE
2 This file is part of KRandr 0.9.5
3 Copyright (C) 2010 Timothy Pearson
4 LibKRandr's homepage : http://www.trinitydesktop.org
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 Send comments and bug fixes to Timothy Pearson <kb9vqf@pearsoncomputing.net>
22
23***************************************************************************/
24
25#include <tqdir.h>
26#include <tqtimer.h>
27#include <tqstringlist.h>
28#include <tqregexp.h>
29
30#include <tdelocale.h>
31#include <tdemessagebox.h>
32#include <tdeapplication.h>
33
34#include <kdebug.h>
35
36#include <stdlib.h>
37#include <unistd.h>
38#include <cmath>
39
40#include "libtderandr.h"
41
42#include <X11/extensions/dpms.h>
43
44// FIXME
45// For now, just use the standalone xrandr program to apply the display settings
46#define USE_XRANDR_PROGRAM
47
48// This routine is courtsey of an answer on "Stack Overflow"
49// It takes an LSB-first int and makes it an MSB-first int (or vice versa)
50unsigned int reverse_bits(unsigned int x)
51{
52 x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
53 x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
54 x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
55 x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
56 return((x >> 16) | (x << 16));
57}
58
59// This routine returns the output of an arbitrary Bash command
60TQString exec(const char * cmd) {
61 TQString bashcommand = cmd;
62 bashcommand = bashcommand.replace("\"", "\\\"");
63 bashcommand = TQString("/bin/bash -c \"%1\" 2>&1").arg(bashcommand);
64 FILE* pipe = popen(bashcommand.ascii(), "r");
65 if (!pipe) return "ERROR";
66 char buffer[128];
67 TQString result = "";
68 while(!feof(pipe)) {
69 if(fgets(buffer, 128, pipe) != NULL) {
70 result += buffer;
71 }
72 }
73 pclose(pipe);
74 result.remove(result.length(), 1);
75 return result;
76}
77
78TQString capitalizeString(TQString in) {
79 return in.left(1).upper() + in.right(in.length()-1);
80}
81
82TQString KRandrSimpleAPI::getIccFileName(TQString profileName, TQString screenName, TQString kde_confdir) {
83 KSimpleConfig *t_config = NULL;
84 KSimpleConfig *t_systemconfig = NULL;
85 int t_numberOfProfiles;
86 TQStringList t_cfgProfiles;
87 TQString retval;
88
89 if ((profileName != NULL) && (profileName != "")) {
90 t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
91 t_config->setGroup(NULL);
92 if (t_config->readBoolEntry("EnableICC", false) == true) {
93 t_config->setGroup(profileName);
94 retval = t_config->readEntry(screenName);
95 }
96 else {
97 retval = "";
98 }
99 delete t_config;
100 }
101 else {
102 t_systemconfig = new KSimpleConfig( kde_confdir + TQString("/kicc/kiccconfigrc") );
103 t_systemconfig->setGroup(NULL);
104 if (t_systemconfig->readBoolEntry("EnableICC", false) == true) {
105 retval = t_systemconfig->readEntry("ICCFile");
106 }
107 else {
108 retval = "";
109 }
110 delete t_systemconfig;
111 }
112
113 return retval;
114}
115
116TQString KRandrSimpleAPI::applyIccFile(TQString screenName, TQString fileName) {
117 int i;
118 int j;
119 Display *randr_display;
120 ScreenInfo *randr_screen_info;
121 XRROutputInfo *output_info;
122
123 int screenNumber = 0;
124
125 if (fileName != "") {
126 // FIXME
127 // This should use the RRSetCrtcGamma function when available
128 // That is the only way to get proper setting when two output are active at the same time
129 // (otherwise in clone mode only one screen is available)
130
131 // HACK
132 // For now, simply exit with no changes if screenName is not an active output
133
134 if (isValid() == true) {
135 screenNumber = -1;
136 randr_display = tqt_xdisplay();
137 randr_screen_info = read_screen_info(randr_display);
138 if (randr_screen_info == NULL) {
139 return "";
140 }
141 j=0;
142 for (i = 0; i < randr_screen_info->n_output; i++) {
143 output_info = randr_screen_info->outputs[i]->info;
144 // Look for ON outputs...
145 if (!randr_screen_info->outputs[i]->cur_crtc) {
146 continue;
147 }
148 // ...that are connected
149 if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
150 continue;
151 }
152 if (output_info->name == screenName) {
153 screenNumber = j;
154 }
155 j++;
156 }
157 freeScreenInfoStructure(randr_screen_info);
158 }
159
160 if (screenNumber >= 0) {
161 // Apply ICC settings with XCalib
162 TQString icc_command;
163 FILE *pipe_xcalib;
164 char xcalib_result[2048];
165 int i;
166 xcalib_result[0]=0;
167
168 icc_command = TQString("xcalib \"%1\"").arg(fileName);
169 if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
170 {
171 printf("Xcalib pipe error\n [xcalib apply]");
172 }
173 else {
174 if (fgets(xcalib_result, 2048, pipe_xcalib)) {
175 pclose(pipe_xcalib);
176 for (i=1;i<2048;i++) {
177 if (xcalib_result[i] == 0) {
178 xcalib_result[i-1]=0;
179 i=2048;
180 }
181 }
182 if (strlen(xcalib_result) > 2) {
183 return xcalib_result;
184 }
185 }
186 else {
187 return "";
188 }
189 }
190 }
191 }
192 else {
193 // Reset ICC profile on this screen
194
195 // FIXME
196 // This should use the RRSetCrtcGamma function when available
197 // That is the only way to get proper setting when two output are active at the same time
198 // (otherwise in clone mode only one screen is available)
199
200 // HACK
201 // For now, simply exit with no changes if screenName is not an active output
202
203 if (isValid() == true) {
204 screenNumber = -1;
205 randr_display = tqt_xdisplay();
206 randr_screen_info = read_screen_info(randr_display);
207 if (randr_screen_info == NULL) {
208 return "";
209 }
210 j=0;
211 for (i = 0; i < randr_screen_info->n_output; i++) {
212 output_info = randr_screen_info->outputs[i]->info;
213 // Look for ON outputs...
214 if (!randr_screen_info->outputs[i]->cur_crtc) {
215 continue;
216 }
217 // ...that are connected
218 if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
219 continue;
220 }
221 if (output_info->name == screenName) {
222 screenNumber = j;
223 }
224 j++;
225 }
226 freeScreenInfoStructure(randr_screen_info);
227 }
228
229 if (screenNumber >= 0) {
230 // Apply ICC settings with XCalib
231 TQString icc_command;
232 FILE *pipe_xcalib;
233 char xcalib_result[2048];
234 int i;
235 xcalib_result[0]=0;
236
237 icc_command = TQString("xcalib -c");
238 if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
239 {
240 printf("Xcalib pipe error\n [xcalib clear]");
241 }
242 else {
243 if (fgets(xcalib_result, 2048, pipe_xcalib)) {
244 pclose(pipe_xcalib);
245 for (i=1;i<2048;i++) {
246 if (xcalib_result[i] == 0) {
247 xcalib_result[i-1]=0;
248 i=2048;
249 }
250 }
251 if (strlen(xcalib_result) > 2) {
252 return xcalib_result;
253 }
254 }
255 else {
256 return "";
257 }
258 }
259 }
260 }
261 return "";
262}
263
264TQString KRandrSimpleAPI::applyIccConfiguration(TQString profileName, TQString kde_confdir) {
265 int i;
266 Display *randr_display;
267 ScreenInfo *randr_screen_info;
268 XRROutputInfo *output_info;
269 KSimpleConfig *t_config;
270
271 int screenNumber = 0;
272 TQString errorstr = "";
273
274 t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
275
276 // Find all screens
277 if (isValid() == true) {
278 randr_display = tqt_xdisplay();
279 randr_screen_info = read_screen_info(randr_display);
280 if (randr_screen_info == NULL) {
281 return "";
282 }
283 for (i = 0; i < randr_screen_info->n_output; i++) {
284 output_info = randr_screen_info->outputs[i]->info;
285 errorstr = applyIccFile(output_info->name, getIccFileName(profileName, output_info->name, kde_confdir));
286 if (errorstr != "") {
287 return errorstr;
288 }
289 }
290 freeScreenInfoStructure(randr_screen_info);
291 }
292 else {
293 return applyIccFile(getIccFileName(profileName, "Default", kde_confdir), "Default");
294 }
295
296 t_config->writeEntry("CurrentProfile", profileName);
297 t_config->sync();
298 delete t_config;
299
300 return "";
301}
302
303TQString KRandrSimpleAPI::getEDIDMonitorName(int card, TQString displayname) {
304 TQString edid;
305 TQByteArray binaryedid = getEDID(card, displayname);
306 if (binaryedid.isNull())
307 return TQString();
308
309 // Get the manufacturer ID
310 unsigned char letter_1 = ((binaryedid[8]>>2) & 0x1F) + 0x40;
311 unsigned char letter_2 = (((binaryedid[8] & 0x03) << 3) | ((binaryedid[9]>>5) & 0x07)) + 0x40;
312 unsigned char letter_3 = (binaryedid[9] & 0x1F) + 0x40;
313 TQChar qletter_1 = TQChar(letter_1);
314 TQChar qletter_2 = TQChar(letter_2);
315 TQChar qletter_3 = TQChar(letter_3);
316 TQString manufacturer_id = TQString("%1%2%3").arg(qletter_1).arg(qletter_2).arg(qletter_3);
317
318 // Get the model ID
319 unsigned int raw_model_id = (((binaryedid[10] << 8) | binaryedid[11]) << 16) & 0xFFFF0000;
320 // Reverse the bit order
321 unsigned int model_id = reverse_bits(raw_model_id);
322
323 // Try to get the model name
324 bool has_friendly_name = false;
325 unsigned char descriptor_block[18];
326 int i;
327 for (i=72;i<90;i++) {
328 descriptor_block[i-72] = binaryedid[i] & 0xFF;
329 }
330 if ((descriptor_block[0] != 0) || (descriptor_block[1] != 0) || (descriptor_block[3] != 0xFC)) {
331 for (i=90;i<108;i++) {
332 descriptor_block[i-90] = binaryedid[i] & 0xFF;
333 }
334 if ((descriptor_block[0] != 0) || (descriptor_block[1] != 0) || (descriptor_block[3] != 0xFC)) {
335 for (i=108;i<126;i++) {
336 descriptor_block[i-108] = binaryedid[i] & 0xFF;
337 }
338 }
339 }
340
341 TQString monitor_name;
342 if ((descriptor_block[0] == 0) && (descriptor_block[1] == 0) && (descriptor_block[3] == 0xFC)) {
343 char* pos = strchr((char *)(descriptor_block+5), '\n');
344 if (pos) {
345 *pos = 0;
346 has_friendly_name = true;
347 monitor_name = TQString((char *)(descriptor_block+5));
348 }
349 else {
350 has_friendly_name = false;
351 }
352 }
353
354 // [FIXME]
355 // Look up manudacturer names if possible!
356
357 if (has_friendly_name)
358 edid = TQString("%1 %2").arg(manufacturer_id).arg(monitor_name);
359 else
360 edid = TQString("%1 0x%2").arg(manufacturer_id).arg(model_id, 0, 16);
361
362 return edid;
363}
364
365TQByteArray KRandrSimpleAPI::getEDID(int card, TQString displayname) {
366 TQFile file(TQString("/sys/class/drm/card%1-%2/edid").arg(card).arg(displayname));
367 if (!file.open (IO_ReadOnly))
368 return TQByteArray();
369 TQByteArray binaryedid = file.readAll();
370 file.close();
371 return binaryedid;
372}
373
374TQString KRandrSimpleAPI::getCurrentProfile () {
375 TQString profileName;
376 KSimpleConfig *t_config;
377
378 t_config = new KSimpleConfig( TQString::fromLatin1( "kiccconfigrc" ));
379 profileName = t_config->readEntry("CurrentProfile");
380 delete t_config;
381 return profileName;
382}
383
384TQString KRandrSimpleAPI::applySystemWideIccConfiguration(TQString kde_confdir) {
385 // Apply ICC settings with XCalib
386 TQString icc_command;
387 FILE *pipe_xcalib;
388 char xcalib_result[2048];
389 int i;
390 xcalib_result[0]=0;
391
392 icc_command = TQString("xcalib \"%1\"").arg(getIccFileName(NULL, "Default", kde_confdir));
393 if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
394 {
395 printf("Xcalib pipe error [xcalib apply]\n");
396 }
397 else {
398 if (fgets(xcalib_result, 2048, pipe_xcalib)) {
399 pclose(pipe_xcalib);
400 for (i=1;i<2048;i++) {
401 if (xcalib_result[i] == 0) {
402 xcalib_result[i-1]=0;
403 i=2048;
404 }
405 }
406 if (strlen(xcalib_result) > 2) {
407 return xcalib_result;
408 }
409 }
410 else {
411 return "";
412 }
413 }
414 return "";
415}
416
417TQStringList KRandrSimpleAPI::getDisplayConfigurationProfiles(TQString kde_confdir) {
418 TQStringList ret;
419
420 TQDir d(kde_confdir + "/displayconfig/");
421 d.setFilter(TQDir::Files);
422 d.setSorting(TQDir::Name);
423
424 const TQFileInfoList *list = d.entryInfoList();
425 if (list) {
426 TQFileInfoListIterator it(*list);
427 TQFileInfo *fi;
428
429 while ((fi = it.current()) != 0) {
430 if (fi->fileName() != "default") {
431 ret.append(fi->fileName());
432 }
433 ++it;
434 }
435 }
436
437 return ret;
438}
439
440bool KRandrSimpleAPI::deleteDisplayConfiguration(TQString profilename, TQString kde_confdir) {
441 TQString fileName = kde_confdir + "/displayconfig/";
442 fileName.append(profilename);
443 return (!unlink(fileName.ascii()));
444}
445
446bool KRandrSimpleAPI::renameDisplayConfiguration(TQString profilename, TQString newprofilename, TQString kde_confdir) {
447 TQString fileName = kde_confdir + "/displayconfig/";
448 TQString newFileName = fileName;
449 fileName.append(profilename);
450 newFileName.append(newprofilename);
451 TQDir d(kde_confdir + "/displayconfig/");
452 return (d.rename(fileName, newFileName));
453}
454
455void KRandrSimpleAPI::saveDisplayConfiguration(bool enable, bool applyonstart, TQString profilename, TQString defaultprofilename, TQString kde_confdir, TQPtrList<SingleScreenData> screenInfoArray) {
456 int i;
457
458 TQString filename;
459
460 filename = "displayglobals";
461 filename.prepend(kde_confdir.append("/"));
462 KSimpleConfig* display_config = new KSimpleConfig( filename );
463 display_config->setGroup("General");
464 display_config->writeEntry("EnableDisplayControl", enable);
465 display_config->writeEntry("ApplySettingsOnStart", applyonstart);
466 display_config->writeEntry("StartupProfileName", defaultprofilename);
467 display_config->sync();
468 delete display_config;
469
470 filename = profilename;
471 if (filename == "") {
472 filename = "default";
473 }
474 filename.prepend(kde_confdir.append("/displayconfig/"));
475
476 display_config = new KSimpleConfig( filename );
477
478 i=0;
479 SingleScreenData *screendata;
480 for ( screendata=screenInfoArray.first(); screendata; screendata=screenInfoArray.next() ) {
481 display_config->setGroup(TQString("SCREEN %1").arg(i));
482 display_config->writeEntry("ScreenUniqueName", screendata->screenUniqueName);
483 display_config->writeEntry("ScreenFriendlyName", screendata->screenFriendlyName);
484 display_config->writeEntry("GenericScreenDetected", screendata->generic_screen_detected);
485 display_config->writeEntry("ScreenConnected", screendata->screen_connected);
486 display_config->writeEntry("Resolutions", screendata->resolutions);
487 display_config->writeEntry("RefreshRates", screendata->refresh_rates);
488 display_config->writeEntry("ColorDepths", screendata->color_depths);
489 display_config->writeEntry("AvailableRotations", screendata->rotations);
490 display_config->writeEntry("CurrentResolution", screendata->current_resolution_index);
491 display_config->writeEntry("CurrentRefreshRate", screendata->current_refresh_rate_index);
492 display_config->writeEntry("CurrentColorDepth", screendata->current_color_depth_index);
493 display_config->writeEntry("CurrentRotation", screendata->current_rotation_index);
494 display_config->writeEntry("CurrentOrientiation", screendata->current_orientation_mask);
495 display_config->writeEntry("GammaRed", screendata->gamma_red);
496 display_config->writeEntry("GammaGreen", screendata->gamma_green);
497 display_config->writeEntry("GammaBlue", screendata->gamma_blue);
498 display_config->writeEntry("CurrentXFlip", screendata->has_x_flip);
499 display_config->writeEntry("CurrentYFlip", screendata->has_y_flip);
500 display_config->writeEntry("SupportsTransformation", screendata->supports_transformations);
501 display_config->writeEntry("IsPrimary", screendata->is_primary);
502 display_config->writeEntry("IsExtended", screendata->is_extended);
503 display_config->writeEntry("AbsXPos", screendata->absolute_x_position);
504 display_config->writeEntry("AbsYPos", screendata->absolute_y_position);
505 display_config->writeEntry("CurrentXPixelCount", screendata->current_x_pixel_count);
506 display_config->writeEntry("CurrentYPixelCount", screendata->current_y_pixel_count);
507 display_config->writeEntry("HasDPMS", screendata->has_dpms);
508 display_config->writeEntry("EnableDPMS", screendata->enable_dpms);
509 display_config->writeEntry("DPMSStandbyDelay", screendata->dpms_standby_delay);
510 display_config->writeEntry("DPMSSuspendDelay", screendata->dpms_suspend_delay);
511 display_config->writeEntry("DPMSPowerDownDelay", screendata->dpms_off_delay);
512 i++;
513 }
514
515 display_config->sync();
516 delete display_config;
517}
518
519TQPoint KRandrSimpleAPI::applyStartupDisplayConfiguration(TQString kde_confdir) {
520 bool applyonstart = getDisplayConfigurationStartupAutoApplyEnabled(kde_confdir);
521 if (applyonstart) {
522 TQString profilename = getDisplayConfigurationStartupAutoApplyName(kde_confdir);
523 return applyDisplayConfiguration(profilename, kde_confdir);
524 }
525 else {
526 return TQPoint();
527 }
528}
529
530TQPoint KRandrSimpleAPI::applyDisplayConfiguration(TQString profilename, TQString kde_confdir) {
531 TQPoint ret;
532
533 bool enabled = getDisplayConfigurationEnabled(kde_confdir);
534 if (profilename == "") {
535 profilename = "default";
536 }
537
538 if (enabled) {
539 TQPtrList<SingleScreenData> screenInfoArray;
540 screenInfoArray = loadDisplayConfiguration(profilename, kde_confdir);
541 if (screenInfoArray.count() > 0) {
542 applyDisplayConfiguration(screenInfoArray, FALSE, kde_confdir);
543 }
544 destroyScreenInformationObject(screenInfoArray);
545 screenInfoArray = readCurrentDisplayConfiguration();
546 ensureMonitorDataConsistency(screenInfoArray);
547 ret = primaryScreenOffsetFromTLC(screenInfoArray);
548 destroyScreenInformationObject(screenInfoArray);
549 }
550
551 return ret;
552}
553
554TQPtrList<SingleScreenData> KRandrSimpleAPI::loadDisplayConfiguration(TQString profilename, TQString kde_confdir) {
555 int i;
556
557 TQString filename;
558 filename = profilename;
559 if (filename == "") {
560 filename = "default";
561 }
562 filename.prepend(kde_confdir.append("/displayconfig/"));
563
564 KSimpleConfig* display_config = new KSimpleConfig( filename );
565
566 TQStringList grouplist = display_config->groupList();
567 SingleScreenData *screendata;
568 TQPtrList<SingleScreenData> screenInfoArray;
569 for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
570 if ((*it).startsWith("SCREEN ")) {
571 display_config->setGroup(*it);
572 i = ((*it).remove("SCREEN ")).toInt();
573 screendata = new SingleScreenData;
574 screenInfoArray.append(screendata);
575 screendata->screenUniqueName = display_config->readEntry("ScreenUniqueName");
576 screendata->screenFriendlyName = display_config->readEntry("ScreenFriendlyName");
577 screendata->generic_screen_detected = display_config->readBoolEntry("GenericScreenDetected");
578 screendata->screen_connected = display_config->readBoolEntry("ScreenConnected");
579 screendata->resolutions = display_config->readListEntry("Resolutions");
580 screendata->refresh_rates = display_config->readListEntry("RefreshRates");
581 screendata->color_depths = display_config->readListEntry("ColorDepths");
582 screendata->rotations = display_config->readListEntry("AvailableRotations");
583 screendata->current_resolution_index = display_config->readNumEntry("CurrentResolution");
584 screendata->current_refresh_rate_index = display_config->readNumEntry("CurrentRefreshRate");
585 screendata->current_color_depth_index = display_config->readNumEntry("CurrentColorDepth");
586 screendata->current_rotation_index = display_config->readNumEntry("CurrentRotation");
587 screendata->current_orientation_mask = display_config->readNumEntry("CurrentOrientiation");
588 screendata->gamma_red = display_config->readDoubleNumEntry("GammaRed");
589 screendata->gamma_green = display_config->readDoubleNumEntry("GammaGreen");
590 screendata->gamma_blue = display_config->readDoubleNumEntry("GammaBlue");
591 screendata->has_x_flip = display_config->readBoolEntry("CurrentXFlip");
592 screendata->has_y_flip = display_config->readBoolEntry("CurrentYFlip");
593 screendata->supports_transformations = display_config->readBoolEntry("SupportsTransformation");
594 screendata->is_primary = display_config->readBoolEntry("IsPrimary");
595 screendata->is_extended = display_config->readBoolEntry("IsExtended");
596 screendata->absolute_x_position = display_config->readNumEntry("AbsXPos");
597 screendata->absolute_y_position = display_config->readNumEntry("AbsYPos");
598 screendata->current_x_pixel_count = display_config->readNumEntry("CurrentXPixelCount");
599 screendata->current_y_pixel_count = display_config->readNumEntry("CurrentYPixelCount");
600 screendata->has_dpms = display_config->readBoolEntry("HasDPMS");
601 screendata->enable_dpms = display_config->readBoolEntry("EnableDPMS");
602 screendata->dpms_standby_delay = display_config->readNumEntry("DPMSStandbyDelay");
603 screendata->dpms_suspend_delay = display_config->readNumEntry("DPMSSuspendDelay");
604 screendata->dpms_off_delay = display_config->readNumEntry("DPMSPowerDownDelay");
605 }
606 }
607
608 delete display_config;
609
610 return screenInfoArray;
611}
612
613int KRandrSimpleAPI::getHardwareRotationFlags(SingleScreenData* screendata) {
614 int rotationFlags = 0;
615 if (screendata->current_rotation_index == ROTATION_0_DEGREES_INDEX) {
616 rotationFlags = rotationFlags | RandRScreen::Rotate0;
617 }
618 else if (screendata->current_rotation_index == ROTATION_90_DEGREES_INDEX) {
619 rotationFlags = rotationFlags | RandRScreen::Rotate90;
620 }
621 else if (screendata->current_rotation_index == ROTATION_180_DEGREES_INDEX) {
622 rotationFlags = rotationFlags | RandRScreen::Rotate180;
623 }
624 else if (screendata->current_rotation_index == ROTATION_270_DEGREES_INDEX) {
625 rotationFlags = rotationFlags | RandRScreen::Rotate270;
626 }
627 if (screendata->has_x_flip) {
628 rotationFlags = rotationFlags | RandRScreen::ReflectX;
629 }
630 if (screendata->has_y_flip) {
631 rotationFlags = rotationFlags | RandRScreen::ReflectY;
632 }
633 return rotationFlags;
634}
635
636#define USE_XRANDR_PROGRAM
637
638bool KRandrSimpleAPI::applyDisplayConfiguration(TQPtrList<SingleScreenData> screenInfoArray, bool test, TQString kde_confdir) {
639 int i;
640 int j;
641 bool accepted = true;
642 Display *randr_display;
643 XRROutputInfo *output_info;
644 ScreenInfo *randr_screen_info;
645
646 SingleScreenData *screendata;
647
648 TQPtrList<SingleScreenData> oldconfig;
649 if (test == TRUE) {
650 oldconfig = readCurrentDisplayConfiguration();
651 }
652
653 if (isValid() == true) {
654#ifdef USE_XRANDR_PROGRAM
655 // Assemble the command string for xrandr
656 TQString command;
657 command = "xrandr";
658
659 randr_display = tqt_xdisplay();
660 randr_screen_info = read_screen_info(randr_display);
661 for (i = 0; i < screenInfoArray.count(); i++) {
662 screendata = screenInfoArray.at(i);
663 if (screendata) {
664 output_info = randr_screen_info->outputs[i]->info;
665 command.append(" --output ").append(output_info->name);
666 if (screendata->is_primary || screendata->is_extended) {
667 command.append(TQString(" --mode %1x%2").arg(screendata->current_x_pixel_count).arg(screendata->current_y_pixel_count));
668 command.append(TQString(" --pos %1x%2").arg(screendata->absolute_x_position).arg(screendata->absolute_y_position));
669 command.append(TQString(" --refresh %1").arg(atoi((*screendata->refresh_rates.at(screendata->current_refresh_rate_index)).ascii())));
670 command.append(TQString(" --gamma %1:%2:%3").arg(screendata->gamma_red).arg(screendata->gamma_green).arg(screendata->gamma_blue));
671 if (screendata->current_rotation_index == ROTATION_0_DEGREES_INDEX) command.append(" --rotate ").append("normal");
672 if (screendata->current_rotation_index == ROTATION_90_DEGREES_INDEX) command.append(" --rotate ").append("left");
673 if (screendata->current_rotation_index == ROTATION_180_DEGREES_INDEX) command.append(" --rotate ").append("inverted");
674 if (screendata->current_rotation_index == ROTATION_270_DEGREES_INDEX) command.append(" --rotate ").append("right");
675 if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("normal");
676 if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("x");
677 if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("y");
678 if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("xy");
679 if (screendata->is_primary) {
680 command.append(" --primary");
681 }
682 }
683 else {
684 command.append(" --off");
685 }
686 }
687 else {
688 printf("[WARNING] Unable to find configuration for monitor %d; settings may not be correctly applied...\n", i); fflush(stdout);
689 }
690 }
691 freeScreenInfoStructure(randr_screen_info);
692
693 TQString xrandr_command_output = exec(command.ascii());
694 xrandr_command_output = xrandr_command_output.stripWhiteSpace();
695 if (test) {
696 // In case gamma settings is not supported, try again without '--gamma' parameter
697 if (xrandr_command_output == "xrandr: Gamma size is 0.") {
698 command = command.replace(TQRegExp("--gamma [0-9\\.]*:[0-9\\.]*:[0-9\\.]*"), "");
699 xrandr_command_output = exec(command.ascii());
700 xrandr_command_output = xrandr_command_output.stripWhiteSpace();
701 }
702
703 if(xrandr_command_output.startsWith("xrandr: Failed to get size of gamma for output")) {
704 KMessageBox::sorry(0, xrandr_command_output, i18n("Setting gamma failed."));
705 } else if (xrandr_command_output != "") {
706 applyDisplayConfiguration(oldconfig, FALSE, kde_confdir);
707 accepted = false;
708 destroyScreenInformationObject(oldconfig);
709 KMessageBox::sorry(0, xrandr_command_output, i18n("XRandR encountered a problem"));
710 return accepted;
711 }
712 }
713#else
714 randr_display = tqt_xdisplay();
715 randr_screen_info = read_screen_info(randr_display);
716 // Turn off all displays
717 for (i = 0; i < screenInfoArray.count(); i++) {
718 screendata = screenInfoArray.at(i);
719 output_info = randr_screen_info->outputs[i]->info;
720
721 randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
722 randr_screen_info->cur_output = randr_screen_info->outputs[i];
723 randr_screen_info->cur_output->auto_set = 0;
724 randr_screen_info->cur_output->off_set = 1;
725 output_off (randr_screen_info, randr_screen_info->cur_output);
726 j=main_low_apply(randr_screen_info);
727 }
728 freeScreenInfoStructure(randr_screen_info);
729 randr_screen_info = read_screen_info(randr_display);
730 // Turn on the primary display
731 for (i = 0; i < screenInfoArray.count(); i++) {
732 screendata = screenInfoArray.at(i);
733 output_info = randr_screen_info->outputs[i]->info;
734
735 if (screendata->is_primary == true) {
736 randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
737 randr_screen_info->cur_output = randr_screen_info->outputs[i];
738 randr_screen_info->cur_output->auto_set = 1;
739 randr_screen_info->cur_output->off_set = 0;
740 output_auto (randr_screen_info, randr_screen_info->cur_output);
741 j=main_low_apply(randr_screen_info);
742 }
743 }
744 freeScreenInfoStructure(randr_screen_info);
745 // Handle the remaining displays
746 randr_screen_info = read_screen_info(randr_display);
747 for (i = 0; i < screenInfoArray.count(); i++) {
748 screendata = screenInfoArray.at(i);
749 output_info = randr_screen_info->outputs[i]->info;
750
751 // Activate or deactivate the screens as necessary
752 randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
753 randr_screen_info->cur_output = randr_screen_info->outputs[i];
754 if (screendata->is_primary == false) {
755 if (screendata->is_primary || screendata->is_extended) {
756 randr_screen_info->cur_output->auto_set = 1;
757 randr_screen_info->cur_output->off_set = 0;
758 output_auto (randr_screen_info, randr_screen_info->cur_output);
759 j=main_low_apply(randr_screen_info);
760 }
761 else {
762 randr_screen_info->cur_output->auto_set = 0;
763 randr_screen_info->cur_output->off_set = 1;
764 output_off (randr_screen_info, randr_screen_info->cur_output);
765 j=main_low_apply(randr_screen_info);
766 }
767 }
768 }
769 freeScreenInfoStructure(randr_screen_info);
770 randr_screen_info = read_screen_info(randr_display);
771 for (i = 0; i < screenInfoArray.count(); i++) {
772 screendata = screenInfoArray.at(i);
773 output_info = randr_screen_info->outputs[i]->info;
774
775 if (screendata->is_primary || screendata->is_extended) {
776 // Set rotation, refresh rate, and size
777 RandRScreen *cur_screen = new RandRScreen(i);
778 cur_screen->proposeSize(screendata->current_resolution_index);
779 cur_screen->proposeRefreshRate(screendata->current_refresh_rate_index);
780 cur_screen->proposeRotation(getHardwareRotationFlags(screendata));
781 cur_screen->applyProposed();
782 delete cur_screen;
783
784 // Force data reload
785 randr_screen_info = read_screen_info(randr_display);
786 output_info = randr_screen_info->outputs[i]->info;
787
788 // Finally, set the screen's position
789 randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
790 if (randr_screen_info->cur_crtc) {
791 randr_screen_info->cur_crtc->cur_x = screendata->absolute_x_position;
792 randr_screen_info->cur_crtc->cur_y = screendata->absolute_y_position;
793 j=main_low_apply(randr_screen_info);
794 }
795 }
796 }
797 freeScreenInfoStructure(randr_screen_info);
798#endif
799 }
800
801 applyDisplayGamma(screenInfoArray);
802 applyDisplayDPMS(screenInfoArray);
803 TQString current_icc_profile = getCurrentProfile();
804 applySystemWideIccConfiguration(kde_confdir);
805 applyIccConfiguration(current_icc_profile, kde_confdir);
806
807 if (test == TRUE) {
808 int ret = showTestConfigurationDialog();
809 if (!ret) {
810 applyDisplayConfiguration(oldconfig, FALSE, kde_confdir);
811 accepted = false;
812 }
813 destroyScreenInformationObject(oldconfig);
814 }
815
816 return accepted;
817}
818
819TQPtrList<SingleScreenData> KRandrSimpleAPI::copyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray) {
820 SingleScreenData *origscreendata;
821 SingleScreenData *copyscreendata;
822 TQPtrList<SingleScreenData> retArray;
823 for ( origscreendata = screenInfoArray.first(); origscreendata; origscreendata = screenInfoArray.next() ) {
824 copyscreendata = new SingleScreenData;
825 *copyscreendata = *origscreendata;
826 retArray.append(copyscreendata);
827 }
828 return retArray;
829}
830
831void KRandrSimpleAPI::destroyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray) {
832 SingleScreenData *screendata;
833 for ( screendata = screenInfoArray.first(); screendata; screendata = screenInfoArray.next() ) {
834 screenInfoArray.remove(screendata);
835 delete screendata;
836 }
837}
838
839void KRandrSimpleAPI::ensureMonitorDataConsistency(TQPtrList<SingleScreenData> screenInfoArray) {
840 int i;
841 SingleScreenData *screendata;
842
843 int numberOfScreens = screenInfoArray.count();
844
845 for (i=0;i<numberOfScreens;i++) {
846 screendata = screenInfoArray.at(i);
847 if (!screendata->screen_connected) {
848 screendata->is_primary = false;
849 screendata->is_extended = false;
850 }
851 }
852
853 bool has_primary_monitor = false;
854 for (i=0;i<numberOfScreens;i++) {
855 screendata = screenInfoArray.at(i);
856 if (screendata->is_primary) {
857 has_primary_monitor = true;
858 }
859 }
860 if (!has_primary_monitor) {
861 for (i=0;i<numberOfScreens;i++) {
862 screendata = screenInfoArray.at(i);
863 if (!has_primary_monitor) {
864 if (screendata->screen_connected && screendata->is_extended) {
865 screendata->is_primary = true;
866 screendata->is_extended = true;
867 has_primary_monitor = true;
868 }
869 }
870 }
871 }
872 if (!has_primary_monitor) {
873 for (i=0;i<numberOfScreens;i++) {
874 screendata = screenInfoArray.at(i);
875 if (!has_primary_monitor) {
876 if (screendata->screen_connected) {
877 screendata->is_primary = true;
878 screendata->is_extended = true;
879 has_primary_monitor = true;
880 }
881 }
882 }
883 }
884
885 bool found_first_primary_monitor = false;
886 for (i=0;i<numberOfScreens;i++) {
887 screendata = screenInfoArray.at(i);
888 if (screendata->is_primary) {
889 if (!found_first_primary_monitor) {
890 found_first_primary_monitor = true;
891 }
892 else {
893 screendata->is_primary = false;
894 }
895 }
896 }
897
898 for (i=0;i<numberOfScreens;i++) {
899 screendata = screenInfoArray.at(i);
900 if (screendata->is_primary) {
901 screendata->is_extended = true;
902 }
903 }
904
905 for (i=0;i<numberOfScreens;i++) {
906 screendata = screenInfoArray.at(i);
907 TQString resolutionstring = screendata->resolutions[screendata->current_resolution_index];
908 int separator_pos = resolutionstring.find(" x ");
909 TQString x_res_string = resolutionstring.left(separator_pos);
910 TQString y_res_string = resolutionstring.right(resolutionstring.length()-separator_pos-3);
911 screendata->current_x_pixel_count = x_res_string.toInt();
912 screendata->current_y_pixel_count = y_res_string.toInt();
913 screendata->current_orientation_mask = getHardwareRotationFlags(screendata);
914 }
915
916 // Each screen's absolute position is given relative to the primary monitor
917 // Fix up the absolute positions
918 int primary_offset_x = 0;
919 int primary_offset_y = 0;
920 for (i=0;i<numberOfScreens;i++) {
921 screendata = screenInfoArray.at(i);
922 if (screendata->is_primary) {
923 primary_offset_x = screendata->absolute_x_position;
924 primary_offset_y = screendata->absolute_y_position;
925 primary_offset_x = primary_offset_x * (-1);
926 primary_offset_y = primary_offset_y * (-1);
927 }
928 }
929 for (i=0;i<numberOfScreens;i++) {
930 screendata = screenInfoArray.at(i);
931 screendata->absolute_x_position = screendata->absolute_x_position + primary_offset_x;
932 screendata->absolute_y_position = screendata->absolute_y_position + primary_offset_y;
933 }
934}
935
936TQPoint KRandrSimpleAPI::primaryScreenOffsetFromTLC(TQPtrList<SingleScreenData> screenInfoArray) {
937 int i;
938 SingleScreenData *screendata;
939 int numberOfScreens = screenInfoArray.count();
940
941 int primary_offset_x = 0;
942 int primary_offset_y = 0;
943 for (i=0;i<numberOfScreens;i++) {
944 screendata = screenInfoArray.at(i);
945 if (screendata->absolute_x_position < primary_offset_x) {
946 primary_offset_x = screendata->absolute_x_position;
947 }
948 if (screendata->absolute_y_position < primary_offset_y) {
949 primary_offset_y = screendata->absolute_y_position;
950 }
951 }
952 primary_offset_x = primary_offset_x * (-1);
953 primary_offset_y = primary_offset_y * (-1);
954
955 return TQPoint(primary_offset_x, primary_offset_y);
956}
957
958HotPlugRulesList KRandrSimpleAPI::getHotplugRules(TQString kde_confdir) {
959 int i;
960 TQString filename;
961 HotPlugRulesList ret;
962
963 filename = "displayglobals";
964 filename.prepend(kde_confdir.append("/"));
965 KSimpleConfig* display_config = new KSimpleConfig( filename );
966
967 TQStringList grouplist = display_config->groupList();
968 for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
969 if (!(*it).startsWith("Hotplug-Rule")) {
970 continue;
971 }
972 HotPlugRule rule;
973 display_config->setGroup(*it);
974 rule.outputs = display_config->readListEntry("Outputs");
975 rule.states = display_config->readIntListEntry("States");
976 rule.profileName = display_config->readEntry("Profile");
977 ret.append(rule);
978 }
979 delete display_config;
980
981 return ret;
982}
983
984void KRandrSimpleAPI::saveHotplugRules(HotPlugRulesList rules, TQString kde_confdir) {
985 int i;
986 TQString filename;
987
988 filename = "displayglobals";
989 filename.prepend(kde_confdir.append("/"));
990 KSimpleConfig* display_config = new KSimpleConfig( filename );
991 TQStringList grouplist = display_config->groupList();
992 for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
993 if (!(*it).startsWith("Hotplug-Rule")) {
994 continue;
995 }
996 display_config->deleteGroup(*it, true, false);
997 }
998 HotPlugRulesList::Iterator it;
999 i=0;
1000 for (it=rules.begin(); it != rules.end(); ++it) {
1001 display_config->setGroup(TQString("Hotplug-Rule%1").arg(i));
1002 display_config->writeEntry("Outputs", (*it).outputs);
1003 display_config->writeEntry("States", (*it).states);
1004 display_config->writeEntry("Profile", (*it).profileName);
1005 i++;
1006 }
1007 display_config->sync();
1008 delete display_config;
1009}
1010
1011bool KRandrSimpleAPI::getDisplayConfigurationEnabled(TQString kde_confdir) {
1012 TQString filename = "displayglobals";
1013 filename.prepend(kde_confdir.append("/"));
1014 KSimpleConfig* display_config = new KSimpleConfig( filename );
1015 display_config->setGroup("General");
1016 bool enabled = display_config->readBoolEntry("EnableDisplayControl", false);
1017 delete display_config;
1018
1019 return enabled;
1020}
1021
1022bool KRandrSimpleAPI::getDisplayConfigurationStartupAutoApplyEnabled(TQString kde_confdir) {
1023 TQString filename = "displayglobals";
1024 filename.prepend(kde_confdir.append("/"));
1025 KSimpleConfig* display_config = new KSimpleConfig( filename );
1026 display_config->setGroup("General");
1027 bool applyonstart = display_config->readBoolEntry("ApplySettingsOnStart", false);
1028 delete display_config;
1029
1030 return applyonstart;
1031}
1032
1033TQString KRandrSimpleAPI::getDisplayConfigurationStartupAutoApplyName(TQString kde_confdir) {
1034 TQString filename = "displayglobals";
1035 filename.prepend(kde_confdir.append("/"));
1036 KSimpleConfig* display_config = new KSimpleConfig( filename );
1037 display_config->setGroup("General");
1038 TQString profilename = display_config->readEntry("StartupProfileName", "");
1039 delete display_config;
1040
1041 return profilename;
1042}
1043
1044void KRandrSimpleAPI::applyHotplugRules(TQString kde_confdir) {
1045 bool enabled = getDisplayConfigurationEnabled(kde_confdir);
1046 if (!enabled) {
1047 return;
1048 }
1049
1050 HotPlugRulesList rules = getHotplugRules(kde_confdir);
1051 TQPtrList<SingleScreenData> screenInfoArray = readCurrentDisplayConfiguration();
1052
1053 int i;
1054 int j;
1055 TQString bestRule;
1056 int bestRuleMatchCount = 0;
1057 SingleScreenData *screendata = NULL;
1058 HotPlugRulesList::Iterator it;
1059 for (it=rules.begin(); it != rules.end(); ++it) {
1060 // Compare each rule against the current display configuration
1061 // It an output matches the state given in the rule, increment matchCount
1062 HotPlugRule rule = *it;
1063 int matchCount = 0;
1064 int numberOfScreens = screenInfoArray.count();
1065 for (i=0;i<numberOfScreens;i++) {
1066 screendata = screenInfoArray.at(i);
1067 for (j=0; j<(*it).outputs.count(); j++) {
1068 if ((*it).outputs[j] != screendata->screenUniqueName) {
1069 continue;
1070 }
1071 if ((*it).states[j] == HotPlugRule::Connected) {
1072 if (screendata->screen_connected) {
1073 matchCount++;
1074 }
1075 }
1076 else if ((*it).states[j] == HotPlugRule::Disconnected) {
1077 if (!screendata->screen_connected) {
1078 matchCount++;
1079 }
1080 }
1081 }
1082 }
1083
1084 if (matchCount > bestRuleMatchCount) {
1085 bestRuleMatchCount = matchCount;
1086 bestRule = rule.profileName;
1087 }
1088 }
1089
1090 destroyScreenInformationObject(screenInfoArray);
1091
1092 if (bestRuleMatchCount > 0) {
1093 // At least one rule matched...
1094 // Apply the profile name in bestRule to the display hardware
1095 applyDisplayConfiguration(bestRule, kde_confdir);
1096 }
1097}
1098
1099void KRandrSimpleAPI::applyDisplayGamma(TQPtrList<SingleScreenData> screenInfoArray) {
1100 Display *randr_display;
1101 XRROutputInfo *output_info;
1102 ScreenInfo *randr_screen_info;
1103 XRRCrtcGamma *gamma;
1104
1105 SingleScreenData *screendata;
1106
1107 if (isValid() == true) {
1108 randr_display = tqt_xdisplay();
1109 randr_screen_info = read_screen_info(randr_display);
1110 for (int i = 0; i < screenInfoArray.count(); i++) {
1111 screendata = screenInfoArray.at(i);
1112 output_info = randr_screen_info->outputs[i]->info;
1113 CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
1114 if (!current_crtc) {
1115 continue;
1116 }
1117 // vvvvvvvvv This chunk of code is based on code from the function set_gamma() of xrandr vvvvvvvvvv
1118 int size = XRRGetCrtcGammaSize(randr_display, current_crtc->id);
1119 if (size <= 0 || size > 65536) {
1120 kdWarning() << "Gamma correction table has wrong size." << endl;
1121 continue;
1122 }
1123 gamma = XRRAllocGamma(size);
1124 if (!gamma) {
1125 kdWarning() << "Gamma allocation failed." << endl;
1126 continue;
1127 }
1128 for (int j = 0; j < size; j++) {
1129 if (size == 1) {
1130 gamma->red[j] = 0.0;
1131 gamma->green[j] = 0.0;
1132 gamma->blue[j] = 0.0;
1133 }
1134 else {
1135 gamma->red[j] = fmin(pow((double)j / (double)(size - 1), screendata->gamma_red), 1.0) * 65535.0;
1136 gamma->green[j] = fmin(pow((double)j / (double)(size - 1), screendata->gamma_green), 1.0) * 65535.0;
1137 gamma->blue[j] = fmin(pow((double)j / (double)(size - 1), screendata->gamma_blue), 1.0) * 65535.0;
1138 }
1139 }
1140 XRRSetCrtcGamma(randr_display, current_crtc->id, gamma);
1141 free(gamma);
1142 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1143 }
1144 freeScreenInfoStructure(randr_screen_info);
1145 }
1146}
1147
1148void KRandrSimpleAPI::applyDisplayDPMS(TQPtrList<SingleScreenData> screenInfoArray) {
1149 int i;
1150 Display *randr_display;
1151 XRROutputInfo *output_info;
1152 ScreenInfo *randr_screen_info;
1153 XRRCrtcGamma *gamma;
1154
1155 SingleScreenData *screendata;
1156
1157 if (isValid() == true) {
1158 randr_display = tqt_xdisplay();
1159 randr_screen_info = read_screen_info(randr_display);
1160 for (i = 0; i < screenInfoArray.count(); i++) {
1161 screendata = screenInfoArray.at(i);
1162 output_info = randr_screen_info->outputs[i]->info;
1163 CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
1164 if (!current_crtc) {
1165 continue;
1166 }
1167 if (!screendata->has_dpms) {
1168 continue;
1169 }
1170 if (screendata->enable_dpms) {
1171 DPMSSetTimeouts(randr_display, screendata->dpms_standby_delay, screendata->dpms_suspend_delay, screendata->dpms_off_delay);
1172 DPMSEnable(randr_display);
1173 }
1174 else {
1175 DPMSDisable(randr_display);
1176 }
1177 }
1178 freeScreenInfoStructure(randr_screen_info);
1179 }
1180}
1181
1182void KRandrSimpleAPI::freeScreenInfoStructure(ScreenInfo* screen_info) {
1183 int i;
1184
1185 for (i=0; i<screen_info->n_crtc; i++) {
1186 free(screen_info->crtcs[i]);
1187 }
1188 for (i=0; i<screen_info->n_output; i++) {
1189 free(screen_info->outputs[i]);
1190 }
1191 free(screen_info->outputs);
1192 free(screen_info->crtcs);
1193 free(screen_info);
1194}
1195
1196TQPtrList<SingleScreenData> KRandrSimpleAPI::readCurrentDisplayConfiguration() {
1197 // Discover display information
1198 int i;
1199 int j;
1200
1201 XRROutputInfo *output_info;
1202 SingleScreenData *screendata;
1203 TQPtrList<SingleScreenData> screenInfoArray;
1204
1205 Display *randr_display;
1206 ScreenInfo *randr_screen_info;
1207
1208 // Clear existing info
1209 destroyScreenInformationObject(screenInfoArray);
1210
1211 int numberOfScreens = 0;
1212 if (isValid() == true) {
1213 randr_display = tqt_xdisplay();
1214 randr_screen_info = read_screen_info(randr_display);
1215 for (i = 0; i < randr_screen_info->n_output; i++) {
1216 output_info = randr_screen_info->outputs[i]->info;
1217 CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
1218
1219 // Create new data object
1220 screendata = new SingleScreenData;
1221 screenInfoArray.append(screendata);
1222 screendata->screenUniqueName = TQString(i18n("%1:%2")).arg(":0").arg(capitalizeString(output_info->name)); // [FIXME] How can I get the name of the Xorg graphics driver currently in use?
1223 screendata->screenFriendlyName = TQString(i18n("%1. %2 output on %3")).arg(i+1).arg(capitalizeString(output_info->name)).arg(":0"); // [FIXME] How can I get the name of the Xorg graphics driver currently in use?
1224 screendata->generic_screen_detected = false;
1225
1226 // Attempt to use KMS to find screen EDID and name
1227 TQString edid = getEDIDMonitorName(0, output_info->name); // [FIXME] Don't hardwire to card 0!
1228 if (!edid.isNull()) {
1229 screendata->screenFriendlyName = TQString(i18n("%1. %2 on %3 on card %4")).arg(i+1).arg(edid).arg(capitalizeString(output_info->name)).arg("0"); // [FIXME] How can I get the name of the Xorg graphics driver currently in use?
1230 }
1231
1232 // Get resolutions
1233 bool screen_active;
1234 RandRScreen *cur_screen = 0;
1235 if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
1236 // Output DISCONNECTED
1237 screen_active = false;
1238 }
1239 else {
1240 if (randr_screen_info->outputs[i]->cur_crtc) {
1241 // Output CONNECTED and ON
1242 screen_active = true;
1243 cur_screen = new RandRScreen(i);
1244 }
1245 else {
1246 // Output CONNECTED and OFF
1247 screen_active = false;
1248 cur_screen = new RandRScreen(i);
1249 }
1250 }
1251
1252 // Get DPMS information
1253 screendata->has_dpms = 1; // [FIXME] Master Xorg check for global DPMS support should go here if possible
1254 if (screendata->has_dpms) {
1255 CARD16 dpms_standby_delay;
1256 CARD16 dpms_suspend_delay;
1257 CARD16 dpms_off_delay;
1258 screendata->has_dpms = DPMSGetTimeouts(randr_display, &dpms_standby_delay, &dpms_suspend_delay, &dpms_off_delay);
1259 screendata->dpms_standby_delay = dpms_standby_delay;
1260 screendata->dpms_suspend_delay = dpms_suspend_delay;
1261 screendata->dpms_off_delay = dpms_off_delay;
1262 if (screendata->has_dpms) {
1263 CARD16 power_level;
1264 BOOL enable_dpms;
1265 screendata->has_dpms = DPMSInfo(randr_display, &power_level, &enable_dpms);
1266 screendata->enable_dpms = enable_dpms;
1267 }
1268 }
1269 if (!screendata->has_dpms) {
1270 screendata->enable_dpms = false;
1271 screendata->dpms_standby_delay = 0;
1272 screendata->dpms_suspend_delay = 0;
1273 screendata->dpms_off_delay = 0;
1274 }
1275
1276 if (cur_screen) {
1277 screendata->screen_connected = true;
1278 for (int j = 0; j < cur_screen->numSizes(); j++) {
1279 screendata->resolutions.append(i18n("%1 x %2").arg(cur_screen->pixelSize(j).width()).arg(cur_screen->pixelSize(j).height()));
1280 }
1281 screendata->current_resolution_index = 0;
1282 if (current_crtc) {
1283 screendata->current_resolution_index = screendata->resolutions.findIndex(i18n("%1 x %2").arg(current_crtc->info->width).arg(current_crtc->info->height));
1284 }
1285 if (screendata->current_resolution_index < 0) {
1286 screendata->current_resolution_index = cur_screen->proposedSize();
1287 }
1288
1289 // Get refresh rates
1290 TQStringList rr = cur_screen->refreshRates(screendata->current_resolution_index);
1291 for (TQStringList::Iterator it = rr.begin(); it != rr.end(); ++it) {
1292 screendata->refresh_rates.append(*it);
1293 }
1294 screendata->current_refresh_rate_index = cur_screen->proposedRefreshRate();
1295
1296 // Get color depths
1297 // [FIXME]
1298 screendata->color_depths.append(i18n("Default"));
1299 screendata->current_color_depth_index = 0;
1300
1301 // Get orientation flags
1302 // RandRScreen::Rotate0
1303 // RandRScreen::Rotate90
1304 // RandRScreen::Rotate180
1305 // RandRScreen::Rotate270
1306 // RandRScreen::ReflectX
1307 // RandRScreen::ReflectY
1308
1309 screendata->rotations.append(i18n("0 degrees"));
1310 screendata->rotations.append(i18n("90 degrees"));
1311 screendata->rotations.append(i18n("180 degrees"));
1312 screendata->rotations.append(i18n("270 degrees"));
1313 screendata->supports_transformations = (cur_screen->rotations() != RandRScreen::Rotate0);
1314 if (screendata->supports_transformations) {
1315 screendata->current_orientation_mask = cur_screen->proposedRotation();
1316 switch (screendata->current_orientation_mask & RandRScreen::RotateMask) {
1317 case RandRScreen::Rotate0:
1318 screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1319 break;
1320 case RandRScreen::Rotate90:
1321 screendata->current_rotation_index = ROTATION_90_DEGREES_INDEX;
1322 break;
1323 case RandRScreen::Rotate180:
1324 screendata->current_rotation_index = ROTATION_180_DEGREES_INDEX;
1325 break;
1326 case RandRScreen::Rotate270:
1327 screendata->current_rotation_index = ROTATION_270_DEGREES_INDEX;
1328 break;
1329 default:
1330 // Shouldn't hit this one
1331 Q_ASSERT(screendata->current_orientation_mask & RandRScreen::RotateMask);
1332 screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1333 break;
1334 }
1335 screendata->has_x_flip = (screendata->current_orientation_mask & RandRScreen::ReflectX);
1336 screendata->has_y_flip = (screendata->current_orientation_mask & RandRScreen::ReflectY);
1337 }
1338 else {
1339 screendata->has_x_flip = false;
1340 screendata->has_y_flip = false;
1341 screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1342 }
1343
1344 // Determine if this display is primary and/or extended
1345 RROutput primaryoutput = XRRGetOutputPrimary(tqt_xdisplay(), DefaultRootWindow(tqt_xdisplay()));
1346 if (primaryoutput == randr_screen_info->outputs[i]->id) {
1347 screendata->is_primary = false;
1348 }
1349 else {
1350 screendata->is_primary = true;
1351 }
1352 screendata->is_extended = screen_active;
1353 if (!screendata->is_extended) {
1354 screendata->is_primary = false;
1355 }
1356
1357 // Get this screen's absolute position
1358 screendata->absolute_x_position = 0;
1359 screendata->absolute_y_position = 0;
1360 if (current_crtc) {
1361 screendata->absolute_x_position = current_crtc->info->x;
1362 screendata->absolute_y_position = current_crtc->info->y;
1363 }
1364
1365 // Get this screen's current resolution
1366 screendata->current_x_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).width();
1367 screendata->current_y_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).height();
1368
1369 // Get this screen's current gamma values
1370 // [FIXME]
1371 // This attempts to guess a gamma value based on the LUT settings at 50%
1372 // It may not always be 100% correct, or even anywhere close...
1373 // Essentially it "undoes" the LUT gamma calculation from xrandr
1374 // lut_gamma->green[i] = (pow(i/(size - 1), desired_gamma.green) * (size - 1) * 256);
1375 screendata->gamma_red = 2.2;
1376 screendata->gamma_green = 2.2;
1377 screendata->gamma_blue = 2.2;
1378 if (current_crtc) {
1379 //int slot = 127;
1380 int slot = 7;
1381 int size = XRRGetCrtcGammaSize(randr_display, current_crtc->id);
1382 XRRCrtcGamma *gammastruct = XRRGetCrtcGamma (randr_display, current_crtc->id);
1383 if (size == 1) {
1384 screendata->gamma_red = 0.0;
1385 screendata->gamma_green = 0.0;
1386 screendata->gamma_blue = 0.0;
1387 }
1388 else if (size > 1) {
1389 screendata->gamma_red = log(gammastruct->red[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
1390 screendata->gamma_green = log(gammastruct->green[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
1391 screendata->gamma_blue = log(gammastruct->blue[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
1392 }
1393 }
1394 // Round off the gamma to one decimal place
1395 screendata->gamma_red = floorf(screendata->gamma_red * 10 + 0.5) / 10;
1396 screendata->gamma_green = floorf(screendata->gamma_green * 10 + 0.5) / 10;
1397 screendata->gamma_blue = floorf(screendata->gamma_blue * 10 + 0.5) / 10;
1398
1399 delete cur_screen;
1400 }
1401 else {
1402 // Fill in generic data for this disconnected output
1403 screendata->screenFriendlyName = screendata->screenFriendlyName + TQString(" (") + i18n("disconnected") + TQString(")");
1404 screendata->screen_connected = false;
1405
1406 screendata->resolutions = i18n("Default");
1407 screendata->refresh_rates = i18n("Default");
1408 screendata->color_depths = i18n("Default");
1409 screendata->rotations = i18n("N/A");
1410
1411 screendata->current_resolution_index = 0;
1412 screendata->current_refresh_rate_index = 0;
1413 screendata->current_color_depth_index = 0;
1414
1415 screendata->gamma_red = 2.2;
1416 screendata->gamma_green = 2.2;
1417 screendata->gamma_blue = 2.2;
1418
1419 screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1420 screendata->current_orientation_mask = 0;
1421 screendata->has_x_flip = false;
1422 screendata->has_y_flip = false;
1423 screendata->supports_transformations = false;
1424
1425 screendata->is_primary = false;
1426 screendata->is_extended = false;
1427 screendata->absolute_x_position = 0;
1428 screendata->absolute_y_position = 0;
1429 screendata->current_x_pixel_count = 640;
1430 screendata->current_y_pixel_count = 480;
1431 }
1432
1433 // Check for more screens...
1434 numberOfScreens++;
1435 }
1436
1437 freeScreenInfoStructure(randr_screen_info);
1438 }
1439 else {
1440 screendata = new SingleScreenData;
1441 screenInfoArray.append(screendata);
1442
1443 // Fill in a bunch of generic data
1444 screendata->screenFriendlyName = i18n("Default output on generic video card");
1445 screendata->generic_screen_detected = true;
1446 screendata->screen_connected = true;
1447
1448 screendata->resolutions = i18n("Default");
1449 screendata->refresh_rates = i18n("Default");
1450 screendata->color_depths = i18n("Default");
1451 screendata->rotations = i18n("N/A");
1452
1453 screendata->current_resolution_index = 0;
1454 screendata->current_refresh_rate_index = 0;
1455 screendata->current_color_depth_index = 0;
1456
1457 screendata->gamma_red = 2.2;
1458 screendata->gamma_green = 2.2;
1459 screendata->gamma_blue = 2.2;
1460
1461 screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1462 screendata->current_orientation_mask = 0;
1463 screendata->has_x_flip = false;
1464 screendata->has_y_flip = false;
1465 screendata->supports_transformations = false;
1466
1467 screendata->is_primary = true;
1468 screendata->is_extended = true;
1469 screendata->absolute_x_position = 0;
1470 screendata->absolute_y_position = 0;
1471 screendata->current_x_pixel_count = 640;
1472 screendata->current_y_pixel_count = 480;
1473
1474 numberOfScreens++;
1475 }
1476
1477 bool primary_set = false;
1478 for ( screendata=screenInfoArray.first(); screendata; screendata=screenInfoArray.next() ) {
1479 if (screendata->is_primary) {
1480 primary_set = true;
1481 break;
1482 }
1483 }
1484 // If there is no primary monitor set, xrandr is probably not functioning correctly!
1485 Q_ASSERT(primary_set);
1486 if (!primary_set) {
1487 // [FIXME]
1488 // Set this on the real primary monitor only!
1489 screendata = screenInfoArray.at(0);
1490 screendata->is_primary = true;
1491 }
1492
1493 return screenInfoArray;
1494}
1495
1496TQString KRandrSimpleAPI::clearIccConfiguration() {
1497 // Clear ICC settings with XCalib
1498 TQString icc_command;
1499 FILE *pipe_xcalib;
1500 char xcalib_result[2048];
1501 int i;
1502 xcalib_result[0]=0;
1503
1504 icc_command = TQString("xcalib -c");
1505 if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
1506 {
1507 printf("Xcalib pipe error [xcalib clear]\n");
1508 }
1509 else {
1510 if (fgets(xcalib_result, 2048, pipe_xcalib)) {
1511 pclose(pipe_xcalib);
1512 for (i=1;i<2048;i++) {
1513 if (xcalib_result[i] == 0) {
1514 xcalib_result[i-1]=0;
1515 i=2048;
1516 }
1517 }
1518 if (strlen(xcalib_result) > 2) {
1519 return xcalib_result;
1520 }
1521 }
1522 else {
1523 return "";
1524 }
1525 }
1526 return "";
1527}
1528
1529ScreenInfo* KRandrSimpleAPI::read_screen_info (Display *display)
1530{
1531 return internal_read_screen_info(display);
1532}
1533
1534int KRandrSimpleAPI::set_screen_size (ScreenInfo *screen_info)
1535{
1536 return internal_set_screen_size(screen_info);
1537}
1538
1539void KRandrSimpleAPI::output_auto (ScreenInfo *screen_info, OutputInfo *output_info)
1540{
1541 internal_output_auto (screen_info, output_info);
1542}
1543
1544void KRandrSimpleAPI::output_off(ScreenInfo *screen_info, OutputInfo *output)
1545{
1546 internal_output_off(screen_info, output);
1547}
1548
1549CrtcInfo* KRandrSimpleAPI::auto_find_crtc (ScreenInfo *screen_info, OutputInfo *output_info)
1550{
1551 return internal_auto_find_crtc (screen_info, output_info);
1552}
1553
1554XRRModeInfo *KRandrSimpleAPI::find_mode_by_xid (ScreenInfo *screen_info, RRMode mode_id)
1555{
1556 return internal_find_mode_by_xid (screen_info, mode_id);
1557}
1558
1559int KRandrSimpleAPI::mode_height (XRRModeInfo *mode_info, Rotation rotation)
1560{
1561 return internal_mode_height (mode_info, rotation);
1562}
1563
1564int KRandrSimpleAPI::mode_width (XRRModeInfo *mode_info, Rotation rotation)
1565{
1566 return internal_mode_width (mode_info, rotation);
1567}
1568
1569int KRandrSimpleAPI::get_width_by_output_id (ScreenInfo *screen_info, RROutput output_id)
1570{
1571 return internal_get_width_by_output_id (screen_info, output_id);
1572}
1573
1574int KRandrSimpleAPI::get_height_by_output_id (ScreenInfo *screen_info, RROutput output_id)
1575{
1576 return internal_get_height_by_output_id (screen_info, output_id);
1577}
1578
1579char *KRandrSimpleAPI::get_output_name (ScreenInfo *screen_info, RROutput id)
1580{
1581 return internal_get_output_name (screen_info, id);
1582}
1583
1584Status KRandrSimpleAPI::crtc_apply (CrtcInfo *crtc_info)
1585{
1586 return internal_crtc_apply (crtc_info);
1587}
1588
1589Status KRandrSimpleAPI::crtc_disable (CrtcInfo *crtc)
1590{
1591 return internal_crtc_disable (crtc);
1592}
1593
1594int KRandrSimpleAPI::main_low_apply (ScreenInfo *screen_info)
1595{
1596 return internal_main_low_apply (screen_info);
1597}
1598
1599void KRandrSimpleAPI::set_primary_output (ScreenInfo *screen_info, RROutput output_id)
1600{
1601 internal_output_set_primary(screen_info, output_id);
1602}
1603
1604bool KRandrSimpleAPI::kRandrHasRandr(void)
1605{
1606 return isValid();
1607}
1608
1609const char *KRandrSimpleAPI::kRandrVersion(void)
1610{
1611 return "0.9.5";
1612}
1613
1614const char *KRandrSimpleAPI::kRandrCopyright(void)
1615{
1616 return "LibKRandr 0.9.5 (C)2010 Timothy Pearson <kb9vqf@pearsoncomputing.net>. U.S.A.";
1617}
1618
1619/* * * * * *
1620
1621 Under this line (------) there's only a C wrapper for the KRandrSimpleAPI class
1622
1623* * * * * */
1624const char *kRandrVersion(void)
1625{
1626 return KRandrSimpleAPI::kRandrVersion();
1627}
1628
1629const char *kRandrCopyright(void)
1630{
1631 return KRandrSimpleAPI::kRandrCopyright();
1632}
1633
KSimpleConfig
KSimpleConfig::sync
virtual void sync()
TDEConfigBase::readEntry
TQString readEntry(const TQString &pKey, const TQString &aDefault=TQString::null) const
TDEConfigBase::deleteGroup
bool deleteGroup(const TQString &group, bool bDeep=true, bool bGlobal=false)
TDEConfigBase::readNumEntry
int readNumEntry(const TQString &pKey, int nDefault=0) const
TDEConfigBase::readBoolEntry
bool readBoolEntry(const TQString &pKey, bool bDefault=false) const
TDEConfigBase::readDoubleNumEntry
double readDoubleNumEntry(const TQString &pKey, double nDefault=0.0) const
TDEConfigBase::readIntListEntry
TQValueList< int > readIntListEntry(const TQString &pKey) const
TDEConfigBase::readListEntry
int readListEntry(const TQString &pKey, TQStrList &list, char sep=',') const
TDEConfigBase::writeEntry
void writeEntry(const TQString &pKey, const TQString &pValue, bool bPersistent=true, bool bGlobal=false, bool bNLS=false)
TDEConfigBase::setGroup
void setGroup(const TQString &group)
TDEConfig::groupList
virtual TQStringList groupList() const
kdWarning
kdbgstream kdWarning(int area=0)
endl
kndbgstream & endl(kndbgstream &s)
tdelocale.h

tderandr

Skip menu "tderandr"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

tderandr

Skip menu "tderandr"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tderandr by doxygen 1.9.4
This website is maintained by Timothy Pearson.