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

tderandr

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

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.8.1.2
This website is maintained by Timothy Pearson.