• 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)
50 unsigned 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
60 TQString 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 
78 TQString capitalizeString(TQString in) {
79  return in.left(1).upper() + in.right(in.length()-1);
80 }
81 
82 TQString 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 
116 TQString 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 
264 TQString 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 
303 TQString 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 
365 TQByteArray 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 
374 TQString 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 
384 TQString 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 
417 TQStringList 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 
440 bool KRandrSimpleAPI::deleteDisplayConfiguration(TQString profilename, TQString kde_confdir) {
441  TQString fileName = kde_confdir + "/displayconfig/";
442  fileName.append(profilename);
443  return (!unlink(fileName.ascii()));
444 }
445 
446 bool 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 
455 void 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 
519 TQPoint 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 
530 TQPoint 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 
554 TQPtrList<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 
613 int 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 
638 bool 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 
819 TQPtrList<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 
831 void 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 
839 void 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 
936 TQPoint 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 
958 HotPlugRulesList 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 
984 void 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 
1011 bool 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 
1022 bool 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 
1033 TQString 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 
1044 void 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 
1099 void 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 
1148 void 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 
1182 void 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 
1196 TQPtrList<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 
1496 TQString 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 
1529 ScreenInfo* KRandrSimpleAPI::read_screen_info (Display *display)
1530 {
1531  return internal_read_screen_info(display);
1532 }
1533 
1534 int KRandrSimpleAPI::set_screen_size (ScreenInfo *screen_info)
1535 {
1536  return internal_set_screen_size(screen_info);
1537 }
1538 
1539 void KRandrSimpleAPI::output_auto (ScreenInfo *screen_info, OutputInfo *output_info)
1540 {
1541  internal_output_auto (screen_info, output_info);
1542 }
1543 
1544 void KRandrSimpleAPI::output_off(ScreenInfo *screen_info, OutputInfo *output)
1545 {
1546  internal_output_off(screen_info, output);
1547 }
1548 
1549 CrtcInfo* KRandrSimpleAPI::auto_find_crtc (ScreenInfo *screen_info, OutputInfo *output_info)
1550 {
1551  return internal_auto_find_crtc (screen_info, output_info);
1552 }
1553 
1554 XRRModeInfo *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 
1559 int KRandrSimpleAPI::mode_height (XRRModeInfo *mode_info, Rotation rotation)
1560 {
1561  return internal_mode_height (mode_info, rotation);
1562 }
1563 
1564 int KRandrSimpleAPI::mode_width (XRRModeInfo *mode_info, Rotation rotation)
1565 {
1566  return internal_mode_width (mode_info, rotation);
1567 }
1568 
1569 int 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 
1574 int 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 
1579 char *KRandrSimpleAPI::get_output_name (ScreenInfo *screen_info, RROutput id)
1580 {
1581  return internal_get_output_name (screen_info, id);
1582 }
1583 
1584 Status KRandrSimpleAPI::crtc_apply (CrtcInfo *crtc_info)
1585 {
1586  return internal_crtc_apply (crtc_info);
1587 }
1588 
1589 Status KRandrSimpleAPI::crtc_disable (CrtcInfo *crtc)
1590 {
1591  return internal_crtc_disable (crtc);
1592 }
1593 
1594 int KRandrSimpleAPI::main_low_apply (ScreenInfo *screen_info)
1595 {
1596  return internal_main_low_apply (screen_info);
1597 }
1598 
1599 void KRandrSimpleAPI::set_primary_output (ScreenInfo *screen_info, RROutput output_id)
1600 {
1601  internal_output_set_primary(screen_info, output_id);
1602 }
1603 
1604 bool KRandrSimpleAPI::kRandrHasRandr(void)
1605 {
1606  return isValid();
1607 }
1608 
1609 const char *KRandrSimpleAPI::kRandrVersion(void)
1610 {
1611  return "0.9.5";
1612 }
1613 
1614 const 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 * * * * * */
1624 const char *kRandrVersion(void)
1625 {
1626  return KRandrSimpleAPI::kRandrVersion();
1627 }
1628 
1629 const 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
endl
kndbgstream & endl(kndbgstream &s)
kdWarning
kdbgstream kdWarning(int area=0)
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.1
This website is maintained by Timothy Pearson.