• 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 <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(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  if (screendata->current_rotation_index == ROTATION_0_DEGREES_INDEX) {
614  rotationFlags = rotationFlags | RandRScreen::Rotate0;
615  }
616  else if (screendata->current_rotation_index == ROTATION_90_DEGREES_INDEX) {
617  rotationFlags = rotationFlags | RandRScreen::Rotate90;
618  }
619  else if (screendata->current_rotation_index == ROTATION_180_DEGREES_INDEX) {
620  rotationFlags = rotationFlags | RandRScreen::Rotate180;
621  }
622  else if (screendata->current_rotation_index == ROTATION_270_DEGREES_INDEX) {
623  rotationFlags = rotationFlags | RandRScreen::Rotate270;
624  }
625  if (screendata->has_x_flip) {
626  rotationFlags = rotationFlags | RandRScreen::ReflectX;
627  }
628  if (screendata->has_y_flip) {
629  rotationFlags = rotationFlags | RandRScreen::ReflectY;
630  }
631  return rotationFlags;
632 }
633 
634 #define USE_XRANDR_PROGRAM
635 
636 bool KRandrSimpleAPI::applyDisplayConfiguration(TQPtrList<SingleScreenData> screenInfoArray, bool test, TQString kde_confdir) {
637  int i;
638  int j;
639  bool accepted = true;
640  Display *randr_display;
641  XRROutputInfo *output_info;
642  ScreenInfo *randr_screen_info;
643 
644  SingleScreenData *screendata;
645 
646  TQPtrList<SingleScreenData> oldconfig;
647  if (test == TRUE) {
648  oldconfig = readCurrentDisplayConfiguration();
649  }
650 
651  if (isValid() == true) {
652 #ifdef USE_XRANDR_PROGRAM
653  // Assemble the command string for xrandr
654  TQString command;
655  command = "xrandr";
656 
657  randr_display = tqt_xdisplay();
658  randr_screen_info = read_screen_info(randr_display);
659  for (i = 0; i < screenInfoArray.count(); i++) {
660  screendata = screenInfoArray.at(i);
661  if (screendata) {
662  output_info = randr_screen_info->outputs[i]->info;
663  command.append(" --output ").append(output_info->name);
664  if (screendata->is_primary || screendata->is_extended) {
665  command.append(TQString(" --mode %1x%2").arg(screendata->current_x_pixel_count).arg(screendata->current_y_pixel_count));
666  command.append(TQString(" --pos %1x%2").arg(screendata->absolute_x_position).arg(screendata->absolute_y_position));
667  command.append(TQString(" --refresh %1").arg(atoi((*screendata->refresh_rates.at(screendata->current_refresh_rate_index)).ascii())));
668  command.append(TQString(" --gamma %1:%2:%3").arg(screendata->gamma_red).arg(screendata->gamma_green).arg(screendata->gamma_blue));
669  if (screendata->current_rotation_index == ROTATION_0_DEGREES_INDEX) command.append(" --rotate ").append("normal");
670  if (screendata->current_rotation_index == ROTATION_90_DEGREES_INDEX) command.append(" --rotate ").append("left");
671  if (screendata->current_rotation_index == ROTATION_180_DEGREES_INDEX) command.append(" --rotate ").append("inverted");
672  if (screendata->current_rotation_index == ROTATION_270_DEGREES_INDEX) command.append(" --rotate ").append("right");
673  if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("normal");
674  if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 0)) command.append(" --reflect ").append("x");
675  if ((screendata->has_x_flip == 0) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("y");
676  if ((screendata->has_x_flip == 1) && (screendata->has_y_flip == 1)) command.append(" --reflect ").append("xy");
677  if (screendata->is_primary) {
678  command.append(" --primary");
679  }
680  }
681  else {
682  command.append(" --off");
683  }
684  }
685  else {
686  printf("[WARNING] Unable to find configuration for monitor %d; settings may not be correctly applied...\n", i); fflush(stdout);
687  }
688  }
689  freeScreenInfoStructure(randr_screen_info);
690 
691  TQString xrandr_command_output = exec(command.ascii());
692  xrandr_command_output = xrandr_command_output.stripWhiteSpace();
693  if (test) {
694  // In case gamma settings is not supported, try again without '--gamma' parameter
695  if (xrandr_command_output == "xrandr: Gamma size is 0.") {
696  command = command.replace(TQRegExp("--gamma [0-9\\.]*:[0-9\\.]*:[0-9\\.]*"), "");
697  xrandr_command_output = exec(command.ascii());
698  xrandr_command_output = xrandr_command_output.stripWhiteSpace();
699  }
700 
701  if(xrandr_command_output.startsWith("xrandr: Failed to get size of gamma for output")) {
702  KMessageBox::sorry(0, xrandr_command_output, i18n("Setting gamma failed."));
703  } else if (xrandr_command_output != "") {
704  applyDisplayConfiguration(oldconfig, FALSE, kde_confdir);
705  accepted = false;
706  destroyScreenInformationObject(oldconfig);
707  KMessageBox::sorry(0, xrandr_command_output, i18n("XRandR encountered a problem"));
708  return accepted;
709  }
710  }
711 #else
712  randr_display = tqt_xdisplay();
713  randr_screen_info = read_screen_info(randr_display);
714  // Turn off all displays
715  for (i = 0; i < screenInfoArray.count(); i++) {
716  screendata = screenInfoArray.at(i);
717  output_info = randr_screen_info->outputs[i]->info;
718 
719  randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
720  randr_screen_info->cur_output = randr_screen_info->outputs[i];
721  randr_screen_info->cur_output->auto_set = 0;
722  randr_screen_info->cur_output->off_set = 1;
723  output_off (randr_screen_info, randr_screen_info->cur_output);
724  j=main_low_apply(randr_screen_info);
725  }
726  freeScreenInfoStructure(randr_screen_info);
727  randr_screen_info = read_screen_info(randr_display);
728  // Turn on the primary display
729  for (i = 0; i < screenInfoArray.count(); i++) {
730  screendata = screenInfoArray.at(i);
731  output_info = randr_screen_info->outputs[i]->info;
732 
733  if (screendata->is_primary == true) {
734  randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
735  randr_screen_info->cur_output = randr_screen_info->outputs[i];
736  randr_screen_info->cur_output->auto_set = 1;
737  randr_screen_info->cur_output->off_set = 0;
738  output_auto (randr_screen_info, randr_screen_info->cur_output);
739  j=main_low_apply(randr_screen_info);
740  }
741  }
742  freeScreenInfoStructure(randr_screen_info);
743  // Handle the remaining displays
744  randr_screen_info = read_screen_info(randr_display);
745  for (i = 0; i < screenInfoArray.count(); i++) {
746  screendata = screenInfoArray.at(i);
747  output_info = randr_screen_info->outputs[i]->info;
748 
749  // Activate or deactivate the screens as necessary
750  randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
751  randr_screen_info->cur_output = randr_screen_info->outputs[i];
752  if (screendata->is_primary == false) {
753  if (screendata->is_primary || screendata->is_extended) {
754  randr_screen_info->cur_output->auto_set = 1;
755  randr_screen_info->cur_output->off_set = 0;
756  output_auto (randr_screen_info, randr_screen_info->cur_output);
757  j=main_low_apply(randr_screen_info);
758  }
759  else {
760  randr_screen_info->cur_output->auto_set = 0;
761  randr_screen_info->cur_output->off_set = 1;
762  output_off (randr_screen_info, randr_screen_info->cur_output);
763  j=main_low_apply(randr_screen_info);
764  }
765  }
766  }
767  freeScreenInfoStructure(randr_screen_info);
768  randr_screen_info = read_screen_info(randr_display);
769  for (i = 0; i < screenInfoArray.count(); i++) {
770  screendata = screenInfoArray.at(i);
771  output_info = randr_screen_info->outputs[i]->info;
772 
773  if (screendata->is_primary || screendata->is_extended) {
774  // Set rotation, refresh rate, and size
775  RandRScreen *cur_screen = new RandRScreen(i);
776  cur_screen->proposeSize(screendata->current_resolution_index);
777  cur_screen->proposeRefreshRate(screendata->current_refresh_rate_index);
778  cur_screen->proposeRotation(getHardwareRotationFlags(screendata));
779  cur_screen->applyProposed();
780  delete cur_screen;
781 
782  // Force data reload
783  randr_screen_info = read_screen_info(randr_display);
784  output_info = randr_screen_info->outputs[i]->info;
785 
786  // Finally, set the screen's position
787  randr_screen_info->cur_crtc = randr_screen_info->outputs[i]->cur_crtc;
788  if (randr_screen_info->cur_crtc) {
789  randr_screen_info->cur_crtc->cur_x = screendata->absolute_x_position;
790  randr_screen_info->cur_crtc->cur_y = screendata->absolute_y_position;
791  j=main_low_apply(randr_screen_info);
792  }
793  }
794  }
795  freeScreenInfoStructure(randr_screen_info);
796 #endif
797  }
798 
799  applyDisplayGamma(screenInfoArray);
800  applyDisplayDPMS(screenInfoArray);
801  TQString current_icc_profile = getCurrentProfile();
802  applySystemWideIccConfiguration(kde_confdir);
803  applyIccConfiguration(current_icc_profile, kde_confdir);
804 
805  if (test == TRUE) {
806  int ret = showTestConfigurationDialog();
807  if (!ret) {
808  applyDisplayConfiguration(oldconfig, FALSE, kde_confdir);
809  accepted = false;
810  }
811  destroyScreenInformationObject(oldconfig);
812  }
813 
814  return accepted;
815 }
816 
817 TQPtrList<SingleScreenData> KRandrSimpleAPI::copyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray) {
818  SingleScreenData *origscreendata;
819  SingleScreenData *copyscreendata;
820  TQPtrList<SingleScreenData> retArray;
821  for ( origscreendata = screenInfoArray.first(); origscreendata; origscreendata = screenInfoArray.next() ) {
822  copyscreendata = new SingleScreenData;
823  *copyscreendata = *origscreendata;
824  retArray.append(copyscreendata);
825  }
826  return retArray;
827 }
828 
829 void KRandrSimpleAPI::destroyScreenInformationObject(TQPtrList<SingleScreenData> screenInfoArray) {
830  SingleScreenData *screendata;
831  for ( screendata = screenInfoArray.first(); screendata; screendata = screenInfoArray.next() ) {
832  screenInfoArray.remove(screendata);
833  delete screendata;
834  }
835 }
836 
837 void KRandrSimpleAPI::ensureMonitorDataConsistency(TQPtrList<SingleScreenData> screenInfoArray) {
838  int i;
839  SingleScreenData *screendata;
840 
841  int numberOfScreens = screenInfoArray.count();
842 
843  for (i=0;i<numberOfScreens;i++) {
844  screendata = screenInfoArray.at(i);
845  if (!screendata->screen_connected) {
846  screendata->is_primary = false;
847  screendata->is_extended = false;
848  }
849  }
850 
851  bool has_primary_monitor = false;
852  for (i=0;i<numberOfScreens;i++) {
853  screendata = screenInfoArray.at(i);
854  if (screendata->is_primary) {
855  has_primary_monitor = true;
856  }
857  }
858  if (!has_primary_monitor) {
859  for (i=0;i<numberOfScreens;i++) {
860  screendata = screenInfoArray.at(i);
861  if (!has_primary_monitor) {
862  if (screendata->screen_connected && screendata->is_extended) {
863  screendata->is_primary = true;
864  screendata->is_extended = true;
865  has_primary_monitor = true;
866  }
867  }
868  }
869  }
870  if (!has_primary_monitor) {
871  for (i=0;i<numberOfScreens;i++) {
872  screendata = screenInfoArray.at(i);
873  if (!has_primary_monitor) {
874  if (screendata->screen_connected) {
875  screendata->is_primary = true;
876  screendata->is_extended = true;
877  has_primary_monitor = true;
878  }
879  }
880  }
881  }
882 
883  bool found_first_primary_monitor = false;
884  for (i=0;i<numberOfScreens;i++) {
885  screendata = screenInfoArray.at(i);
886  if (screendata->is_primary) {
887  if (!found_first_primary_monitor) {
888  found_first_primary_monitor = true;
889  }
890  else {
891  screendata->is_primary = false;
892  }
893  }
894  }
895 
896  for (i=0;i<numberOfScreens;i++) {
897  screendata = screenInfoArray.at(i);
898  if (screendata->is_primary) {
899  screendata->is_extended = true;
900  }
901  }
902 
903  for (i=0;i<numberOfScreens;i++) {
904  screendata = screenInfoArray.at(i);
905  TQString resolutionstring = screendata->resolutions[screendata->current_resolution_index];
906  int separator_pos = resolutionstring.find(" x ");
907  TQString x_res_string = resolutionstring.left(separator_pos);
908  TQString y_res_string = resolutionstring.right(resolutionstring.length()-separator_pos-3);
909  screendata->current_x_pixel_count = x_res_string.toInt();
910  screendata->current_y_pixel_count = y_res_string.toInt();
911  screendata->current_orientation_mask = getHardwareRotationFlags(screendata);
912  }
913 
914  // Each screen's absolute position is given relative to the primary monitor
915  // Fix up the absolute positions
916  int primary_offset_x = 0;
917  int primary_offset_y = 0;
918  for (i=0;i<numberOfScreens;i++) {
919  screendata = screenInfoArray.at(i);
920  if (screendata->is_primary) {
921  primary_offset_x = screendata->absolute_x_position;
922  primary_offset_y = screendata->absolute_y_position;
923  primary_offset_x = primary_offset_x * (-1);
924  primary_offset_y = primary_offset_y * (-1);
925  }
926  }
927  for (i=0;i<numberOfScreens;i++) {
928  screendata = screenInfoArray.at(i);
929  screendata->absolute_x_position = screendata->absolute_x_position + primary_offset_x;
930  screendata->absolute_y_position = screendata->absolute_y_position + primary_offset_y;
931  }
932 }
933 
934 TQPoint KRandrSimpleAPI::primaryScreenOffsetFromTLC(TQPtrList<SingleScreenData> screenInfoArray) {
935  int i;
936  SingleScreenData *screendata;
937  int numberOfScreens = screenInfoArray.count();
938 
939  int primary_offset_x = 0;
940  int primary_offset_y = 0;
941  for (i=0;i<numberOfScreens;i++) {
942  screendata = screenInfoArray.at(i);
943  if (screendata->absolute_x_position < primary_offset_x) {
944  primary_offset_x = screendata->absolute_x_position;
945  }
946  if (screendata->absolute_y_position < primary_offset_y) {
947  primary_offset_y = screendata->absolute_y_position;
948  }
949  }
950  primary_offset_x = primary_offset_x * (-1);
951  primary_offset_y = primary_offset_y * (-1);
952 
953  return TQPoint(primary_offset_x, primary_offset_y);
954 }
955 
956 HotPlugRulesList KRandrSimpleAPI::getHotplugRules(TQString kde_confdir) {
957  int i;
958  TQString filename;
959  HotPlugRulesList ret;
960 
961  filename = "displayglobals";
962  filename.prepend(kde_confdir.append("/"));
963  KSimpleConfig* display_config = new KSimpleConfig( filename );
964 
965  TQStringList grouplist = display_config->groupList();
966  for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
967  if (!(*it).startsWith("Hotplug-Rule")) {
968  continue;
969  }
970  HotPlugRule rule;
971  display_config->setGroup(*it);
972  rule.outputs = display_config->readListEntry("Outputs");
973  rule.states = display_config->readIntListEntry("States");
974  rule.profileName = display_config->readEntry("Profile");
975  ret.append(rule);
976  }
977  delete display_config;
978 
979  return ret;
980 }
981 
982 void KRandrSimpleAPI::saveHotplugRules(HotPlugRulesList rules, TQString kde_confdir) {
983  int i;
984  TQString filename;
985 
986  filename = "displayglobals";
987  filename.prepend(kde_confdir.append("/"));
988  KSimpleConfig* display_config = new KSimpleConfig( filename );
989  TQStringList grouplist = display_config->groupList();
990  for ( TQStringList::Iterator it = grouplist.begin(); it != grouplist.end(); ++it ) {
991  if (!(*it).startsWith("Hotplug-Rule")) {
992  continue;
993  }
994  display_config->deleteGroup(*it, true, false);
995  }
996  HotPlugRulesList::Iterator it;
997  i=0;
998  for (it=rules.begin(); it != rules.end(); ++it) {
999  display_config->setGroup(TQString("Hotplug-Rule%1").arg(i));
1000  display_config->writeEntry("Outputs", (*it).outputs);
1001  display_config->writeEntry("States", (*it).states);
1002  display_config->writeEntry("Profile", (*it).profileName);
1003  i++;
1004  }
1005  display_config->sync();
1006  delete display_config;
1007 }
1008 
1009 bool KRandrSimpleAPI::getDisplayConfigurationEnabled(TQString kde_confdir) {
1010  TQString filename = "displayglobals";
1011  filename.prepend(kde_confdir.append("/"));
1012  KSimpleConfig* display_config = new KSimpleConfig( filename );
1013  display_config->setGroup("General");
1014  bool enabled = display_config->readBoolEntry("EnableDisplayControl", false);
1015  delete display_config;
1016 
1017  return enabled;
1018 }
1019 
1020 bool KRandrSimpleAPI::getDisplayConfigurationStartupAutoApplyEnabled(TQString kde_confdir) {
1021  TQString filename = "displayglobals";
1022  filename.prepend(kde_confdir.append("/"));
1023  KSimpleConfig* display_config = new KSimpleConfig( filename );
1024  display_config->setGroup("General");
1025  bool applyonstart = display_config->readBoolEntry("ApplySettingsOnStart", false);
1026  delete display_config;
1027 
1028  return applyonstart;
1029 }
1030 
1031 TQString KRandrSimpleAPI::getDisplayConfigurationStartupAutoApplyName(TQString kde_confdir) {
1032  TQString filename = "displayglobals";
1033  filename.prepend(kde_confdir.append("/"));
1034  KSimpleConfig* display_config = new KSimpleConfig( filename );
1035  display_config->setGroup("General");
1036  TQString profilename = display_config->readEntry("StartupProfileName", "");
1037  delete display_config;
1038 
1039  return profilename;
1040 }
1041 
1042 void KRandrSimpleAPI::applyHotplugRules(TQString kde_confdir) {
1043  bool enabled = getDisplayConfigurationEnabled(kde_confdir);
1044  if (!enabled) {
1045  return;
1046  }
1047 
1048  HotPlugRulesList rules = getHotplugRules(kde_confdir);
1049  TQPtrList<SingleScreenData> screenInfoArray = readCurrentDisplayConfiguration();
1050 
1051  int i;
1052  int j;
1053  TQString bestRule;
1054  int bestRuleMatchCount = 0;
1055  SingleScreenData *screendata = NULL;
1056  HotPlugRulesList::Iterator it;
1057  for (it=rules.begin(); it != rules.end(); ++it) {
1058  // Compare each rule against the current display configuration
1059  // It an output matches the state given in the rule, increment matchCount
1060  HotPlugRule rule = *it;
1061  int matchCount = 0;
1062  int numberOfScreens = screenInfoArray.count();
1063  for (i=0;i<numberOfScreens;i++) {
1064  screendata = screenInfoArray.at(i);
1065  for (j=0; j<(*it).outputs.count(); j++) {
1066  if ((*it).outputs[j] != screendata->screenUniqueName) {
1067  continue;
1068  }
1069  if ((*it).states[j] == HotPlugRule::Connected) {
1070  if (screendata->screen_connected) {
1071  matchCount++;
1072  }
1073  }
1074  else if ((*it).states[j] == HotPlugRule::Disconnected) {
1075  if (!screendata->screen_connected) {
1076  matchCount++;
1077  }
1078  }
1079  }
1080  }
1081 
1082  if (matchCount > bestRuleMatchCount) {
1083  bestRuleMatchCount = matchCount;
1084  bestRule = rule.profileName;
1085  }
1086  }
1087 
1088  destroyScreenInformationObject(screenInfoArray);
1089 
1090  if (bestRuleMatchCount > 0) {
1091  // At least one rule matched...
1092  // Apply the profile name in bestRule to the display hardware
1093  applyDisplayConfiguration(bestRule, kde_confdir);
1094  }
1095 }
1096 
1097 void KRandrSimpleAPI::applyDisplayGamma(TQPtrList<SingleScreenData> screenInfoArray) {
1098  int i;
1099  Display *randr_display;
1100  XRROutputInfo *output_info;
1101  ScreenInfo *randr_screen_info;
1102  XRRCrtcGamma *gamma;
1103 
1104  SingleScreenData *screendata;
1105 
1106  if (isValid() == true) {
1107  randr_display = tqt_xdisplay();
1108  randr_screen_info = read_screen_info(randr_display);
1109  for (i = 0; i < screenInfoArray.count(); i++) {
1110  screendata = screenInfoArray.at(i);
1111  output_info = randr_screen_info->outputs[i]->info;
1112  CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
1113  if (!current_crtc) {
1114  continue;
1115  }
1116  // vvvvvvvvv This chunk of code is borrowed from xrandr vvvvvvvvvv
1117  int size = XRRGetCrtcGammaSize(randr_display, current_crtc->id);
1118  if (!size) {
1119  continue;
1120  }
1121  gamma = XRRAllocGamma(size);
1122  if (!gamma) {
1123  continue;
1124  }
1125  for (i = 0; i < size; i++) {
1126  if (screendata->gamma_red == 1.0)
1127  gamma->red[i] = i << 8;
1128  else
1129  gamma->red[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_red) * (double)(size-1)*256);
1130 
1131  if (screendata->gamma_green == 1.0)
1132  gamma->green[i] = i << 8;
1133  else
1134  gamma->green[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_green) * (double)(size-1)*256);
1135 
1136  if (screendata->gamma_blue == 1.0)
1137  gamma->blue[i] = i << 8;
1138  else
1139  gamma->blue[i] = (pow((double)i/(double)(size-1), (double)screendata->gamma_blue) * (double)(size-1)*256);
1140  }
1141  XRRSetCrtcGamma(randr_display, current_crtc->id, gamma);
1142  free(gamma);
1143  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1144  }
1145  freeScreenInfoStructure(randr_screen_info);
1146  }
1147 }
1148 
1149 void KRandrSimpleAPI::applyDisplayDPMS(TQPtrList<SingleScreenData> screenInfoArray) {
1150  int i;
1151  Display *randr_display;
1152  XRROutputInfo *output_info;
1153  ScreenInfo *randr_screen_info;
1154  XRRCrtcGamma *gamma;
1155 
1156  SingleScreenData *screendata;
1157 
1158  if (isValid() == true) {
1159  randr_display = tqt_xdisplay();
1160  randr_screen_info = read_screen_info(randr_display);
1161  for (i = 0; i < screenInfoArray.count(); i++) {
1162  screendata = screenInfoArray.at(i);
1163  output_info = randr_screen_info->outputs[i]->info;
1164  CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
1165  if (!current_crtc) {
1166  continue;
1167  }
1168  if (!screendata->has_dpms) {
1169  continue;
1170  }
1171  if (screendata->enable_dpms) {
1172  DPMSSetTimeouts(randr_display, screendata->dpms_standby_delay, screendata->dpms_suspend_delay, screendata->dpms_off_delay);
1173  DPMSEnable(randr_display);
1174  }
1175  else {
1176  DPMSDisable(randr_display);
1177  }
1178  }
1179  freeScreenInfoStructure(randr_screen_info);
1180  }
1181 }
1182 
1183 void KRandrSimpleAPI::freeScreenInfoStructure(ScreenInfo* screen_info) {
1184  int i;
1185 
1186  for (i=0; i<screen_info->n_crtc; i++) {
1187  free(screen_info->crtcs[i]);
1188  }
1189  for (i=0; i<screen_info->n_output; i++) {
1190  free(screen_info->outputs[i]);
1191  }
1192  free(screen_info->outputs);
1193  free(screen_info->crtcs);
1194  free(screen_info);
1195 }
1196 
1197 TQPtrList<SingleScreenData> KRandrSimpleAPI::readCurrentDisplayConfiguration() {
1198  // Discover display information
1199  int i;
1200  int j;
1201 
1202  XRROutputInfo *output_info;
1203  SingleScreenData *screendata;
1204  TQPtrList<SingleScreenData> screenInfoArray;
1205 
1206  Display *randr_display;
1207  ScreenInfo *randr_screen_info;
1208 
1209  // Clear existing info
1210  destroyScreenInformationObject(screenInfoArray);
1211 
1212  int numberOfScreens = 0;
1213  if (isValid() == true) {
1214  randr_display = tqt_xdisplay();
1215  randr_screen_info = read_screen_info(randr_display);
1216  for (i = 0; i < randr_screen_info->n_output; i++) {
1217  output_info = randr_screen_info->outputs[i]->info;
1218  CrtcInfo *current_crtc = randr_screen_info->outputs[i]->cur_crtc;
1219 
1220  // Create new data object
1221  screendata = new SingleScreenData;
1222  screenInfoArray.append(screendata);
1223  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?
1224  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?
1225  screendata->generic_screen_detected = false;
1226 
1227  // Attempt to use KMS to find screen EDID and name
1228  TQString edid = getEDIDMonitorName(0, output_info->name); // [FIXME] Don't hardwire to card 0!
1229  if (!edid.isNull()) {
1230  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?
1231  }
1232 
1233  // Get resolutions
1234  bool screen_active;
1235  RandRScreen *cur_screen = 0;
1236  if (RR_Disconnected == randr_screen_info->outputs[i]->info->connection) {
1237  // Output DISCONNECTED
1238  screen_active = false;
1239  }
1240  else {
1241  if (randr_screen_info->outputs[i]->cur_crtc) {
1242  // Output CONNECTED and ON
1243  screen_active = true;
1244  cur_screen = new RandRScreen(i);
1245  }
1246  else {
1247  // Output CONNECTED and OFF
1248  screen_active = false;
1249  cur_screen = new RandRScreen(i);
1250  }
1251  }
1252 
1253  // Get DPMS information
1254  screendata->has_dpms = 1; // [FIXME] Master Xorg check for global DPMS support should go here if possible
1255  if (screendata->has_dpms) {
1256  CARD16 dpms_standby_delay;
1257  CARD16 dpms_suspend_delay;
1258  CARD16 dpms_off_delay;
1259  screendata->has_dpms = DPMSGetTimeouts(randr_display, &dpms_standby_delay, &dpms_suspend_delay, &dpms_off_delay);
1260  screendata->dpms_standby_delay = dpms_standby_delay;
1261  screendata->dpms_suspend_delay = dpms_suspend_delay;
1262  screendata->dpms_off_delay = dpms_off_delay;
1263  if (screendata->has_dpms) {
1264  CARD16 power_level;
1265  BOOL enable_dpms;
1266  screendata->has_dpms = DPMSInfo(randr_display, &power_level, &enable_dpms);
1267  screendata->enable_dpms = enable_dpms;
1268  }
1269  }
1270  if (!screendata->has_dpms) {
1271  screendata->enable_dpms = false;
1272  screendata->dpms_standby_delay = 0;
1273  screendata->dpms_suspend_delay = 0;
1274  screendata->dpms_off_delay = 0;
1275  }
1276 
1277  if (cur_screen) {
1278  screendata->screen_connected = true;
1279  for (int j = 0; j < cur_screen->numSizes(); j++) {
1280  screendata->resolutions.append(i18n("%1 x %2").arg(cur_screen->pixelSize(j).width()).arg(cur_screen->pixelSize(j).height()));
1281  }
1282  screendata->current_resolution_index = 0;
1283  if (current_crtc) {
1284  screendata->current_resolution_index = screendata->resolutions.findIndex(i18n("%1 x %2").arg(current_crtc->info->width).arg(current_crtc->info->height));
1285  }
1286  if (screendata->current_resolution_index < 0) {
1287  screendata->current_resolution_index = cur_screen->proposedSize();
1288  }
1289 
1290  // Get refresh rates
1291  TQStringList rr = cur_screen->refreshRates(screendata->current_resolution_index);
1292  for (TQStringList::Iterator it = rr.begin(); it != rr.end(); ++it) {
1293  screendata->refresh_rates.append(*it);
1294  }
1295  screendata->current_refresh_rate_index = cur_screen->proposedRefreshRate();
1296 
1297  // Get color depths
1298  // [FIXME]
1299  screendata->color_depths.append(i18n("Default"));
1300  screendata->current_color_depth_index = 0;
1301 
1302  // Get orientation flags
1303  // RandRScreen::Rotate0
1304  // RandRScreen::Rotate90
1305  // RandRScreen::Rotate180
1306  // RandRScreen::Rotate270
1307  // RandRScreen::ReflectX
1308  // RandRScreen::ReflectY
1309 
1310  screendata->rotations.append(i18n("0 degrees"));
1311  screendata->rotations.append(i18n("90 degrees"));
1312  screendata->rotations.append(i18n("180 degrees"));
1313  screendata->rotations.append(i18n("270 degrees"));
1314  screendata->supports_transformations = (cur_screen->rotations() != RandRScreen::Rotate0);
1315  if (screendata->supports_transformations) {
1316  screendata->current_orientation_mask = cur_screen->proposedRotation();
1317  switch (screendata->current_orientation_mask & RandRScreen::RotateMask) {
1318  case RandRScreen::Rotate0:
1319  screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1320  break;
1321  case RandRScreen::Rotate90:
1322  screendata->current_rotation_index = ROTATION_90_DEGREES_INDEX;
1323  break;
1324  case RandRScreen::Rotate180:
1325  screendata->current_rotation_index = ROTATION_180_DEGREES_INDEX;
1326  break;
1327  case RandRScreen::Rotate270:
1328  screendata->current_rotation_index = ROTATION_270_DEGREES_INDEX;
1329  break;
1330  default:
1331  // Shouldn't hit this one
1332  Q_ASSERT(screendata->current_orientation_mask & RandRScreen::RotateMask);
1333  screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1334  break;
1335  }
1336  screendata->has_x_flip = (screendata->current_orientation_mask & RandRScreen::ReflectX);
1337  screendata->has_y_flip = (screendata->current_orientation_mask & RandRScreen::ReflectY);
1338  }
1339  else {
1340  screendata->has_x_flip = false;
1341  screendata->has_y_flip = false;
1342  screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1343  }
1344 
1345  // Determine if this display is primary and/or extended
1346  RROutput primaryoutput = XRRGetOutputPrimary(tqt_xdisplay(), DefaultRootWindow(tqt_xdisplay()));
1347  if (primaryoutput == randr_screen_info->outputs[i]->id) {
1348  screendata->is_primary = false;
1349  }
1350  else {
1351  screendata->is_primary = true;
1352  }
1353  screendata->is_extended = screen_active;
1354  if (!screendata->is_extended) {
1355  screendata->is_primary = false;
1356  }
1357 
1358  // Get this screen's absolute position
1359  screendata->absolute_x_position = 0;
1360  screendata->absolute_y_position = 0;
1361  if (current_crtc) {
1362  screendata->absolute_x_position = current_crtc->info->x;
1363  screendata->absolute_y_position = current_crtc->info->y;
1364  }
1365 
1366  // Get this screen's current resolution
1367  screendata->current_x_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).width();
1368  screendata->current_y_pixel_count = cur_screen->pixelSize(screendata->current_resolution_index).height();
1369 
1370  // Get this screen's current gamma values
1371  // [FIXME]
1372  // This attempts to guess a gamma value based on the LUT settings at 50%
1373  // It may not always be 100% correct, or even anywhere close...
1374  // Essentially it "undoes" the LUT gamma calculation from xrandr
1375  // lut_gamma->green[i] = (pow(i/(size - 1), desired_gamma.green) * (size - 1) * 256);
1376  screendata->gamma_red = 2.2;
1377  screendata->gamma_green = 2.2;
1378  screendata->gamma_blue = 2.2;
1379  if (current_crtc) {
1380  //int slot = 127;
1381  int slot = 7;
1382  int size = XRRGetCrtcGammaSize(randr_display, current_crtc->id);
1383  if(size>0) {
1384  XRRCrtcGamma *gammastruct = XRRGetCrtcGamma (randr_display, current_crtc->id);
1385  screendata->gamma_red = log(gammastruct->red[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
1386  screendata->gamma_green = log(gammastruct->green[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
1387  screendata->gamma_blue = log(gammastruct->blue[slot]/((size-1.0)*256.0))/log(slot/(size-1.0));
1388  }
1389  }
1390  // Round off the gamma to one decimal place
1391  screendata->gamma_red = floorf(screendata->gamma_red * 10 + 0.5) / 10;
1392  screendata->gamma_green = floorf(screendata->gamma_green * 10 + 0.5) / 10;
1393  screendata->gamma_blue = floorf(screendata->gamma_blue * 10 + 0.5) / 10;
1394 
1395  delete cur_screen;
1396  }
1397  else {
1398  // Fill in generic data for this disconnected output
1399  screendata->screenFriendlyName = screendata->screenFriendlyName + TQString(" (") + i18n("disconnected") + TQString(")");
1400  screendata->screen_connected = false;
1401 
1402  screendata->resolutions = i18n("Default");
1403  screendata->refresh_rates = i18n("Default");
1404  screendata->color_depths = i18n("Default");
1405  screendata->rotations = i18n("N/A");
1406 
1407  screendata->current_resolution_index = 0;
1408  screendata->current_refresh_rate_index = 0;
1409  screendata->current_color_depth_index = 0;
1410 
1411  screendata->gamma_red = 2.2;
1412  screendata->gamma_green = 2.2;
1413  screendata->gamma_blue = 2.2;
1414 
1415  screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1416  screendata->current_orientation_mask = 0;
1417  screendata->has_x_flip = false;
1418  screendata->has_y_flip = false;
1419  screendata->supports_transformations = false;
1420 
1421  screendata->is_primary = false;
1422  screendata->is_extended = false;
1423  screendata->absolute_x_position = 0;
1424  screendata->absolute_y_position = 0;
1425  screendata->current_x_pixel_count = 640;
1426  screendata->current_y_pixel_count = 480;
1427  }
1428 
1429  // Check for more screens...
1430  numberOfScreens++;
1431  }
1432 
1433  freeScreenInfoStructure(randr_screen_info);
1434  }
1435  else {
1436  screendata = new SingleScreenData;
1437  screenInfoArray.append(screendata);
1438 
1439  // Fill in a bunch of generic data
1440  screendata->screenFriendlyName = i18n("Default output on generic video card");
1441  screendata->generic_screen_detected = true;
1442  screendata->screen_connected = true;
1443 
1444  screendata->resolutions = i18n("Default");
1445  screendata->refresh_rates = i18n("Default");
1446  screendata->color_depths = i18n("Default");
1447  screendata->rotations = i18n("N/A");
1448 
1449  screendata->current_resolution_index = 0;
1450  screendata->current_refresh_rate_index = 0;
1451  screendata->current_color_depth_index = 0;
1452 
1453  screendata->gamma_red = 2.2;
1454  screendata->gamma_green = 2.2;
1455  screendata->gamma_blue = 2.2;
1456 
1457  screendata->current_rotation_index = ROTATION_0_DEGREES_INDEX;
1458  screendata->current_orientation_mask = 0;
1459  screendata->has_x_flip = false;
1460  screendata->has_y_flip = false;
1461  screendata->supports_transformations = false;
1462 
1463  screendata->is_primary = true;
1464  screendata->is_extended = true;
1465  screendata->absolute_x_position = 0;
1466  screendata->absolute_y_position = 0;
1467  screendata->current_x_pixel_count = 640;
1468  screendata->current_y_pixel_count = 480;
1469 
1470  numberOfScreens++;
1471  }
1472 
1473  bool primary_set = false;
1474  for ( screendata=screenInfoArray.first(); screendata; screendata=screenInfoArray.next() ) {
1475  if (screendata->is_primary) {
1476  primary_set = true;
1477  break;
1478  }
1479  }
1480  // If there is no primary monitor set, xrandr is probably not functioning correctly!
1481  Q_ASSERT(primary_set);
1482  if (!primary_set) {
1483  // [FIXME]
1484  // Set this on the real primary monitor only!
1485  screendata = screenInfoArray.at(0);
1486  screendata->is_primary = true;
1487  }
1488 
1489  return screenInfoArray;
1490 }
1491 
1492 TQString KRandrSimpleAPI::clearIccConfiguration() {
1493  // Clear ICC settings with XCalib
1494  TQString icc_command;
1495  FILE *pipe_xcalib;
1496  char xcalib_result[2048];
1497  int i;
1498  xcalib_result[0]=0;
1499 
1500  icc_command = TQString("xcalib -c");
1501  if ((pipe_xcalib = popen(icc_command.ascii(), "r")) == NULL)
1502  {
1503  printf("Xcalib pipe error [xcalib clear]\n");
1504  }
1505  else {
1506  if (fgets(xcalib_result, 2048, pipe_xcalib)) {
1507  pclose(pipe_xcalib);
1508  for (i=1;i<2048;i++) {
1509  if (xcalib_result[i] == 0) {
1510  xcalib_result[i-1]=0;
1511  i=2048;
1512  }
1513  }
1514  if (strlen(xcalib_result) > 2) {
1515  return xcalib_result;
1516  }
1517  }
1518  else {
1519  return "";
1520  }
1521  }
1522  return "";
1523 }
1524 
1525 ScreenInfo* KRandrSimpleAPI::read_screen_info (Display *display)
1526 {
1527  return internal_read_screen_info(display);
1528 }
1529 
1530 int KRandrSimpleAPI::set_screen_size (ScreenInfo *screen_info)
1531 {
1532  return internal_set_screen_size(screen_info);
1533 }
1534 
1535 void KRandrSimpleAPI::output_auto (ScreenInfo *screen_info, OutputInfo *output_info)
1536 {
1537  internal_output_auto (screen_info, output_info);
1538 }
1539 
1540 void KRandrSimpleAPI::output_off(ScreenInfo *screen_info, OutputInfo *output)
1541 {
1542  internal_output_off(screen_info, output);
1543 }
1544 
1545 CrtcInfo* KRandrSimpleAPI::auto_find_crtc (ScreenInfo *screen_info, OutputInfo *output_info)
1546 {
1547  return internal_auto_find_crtc (screen_info, output_info);
1548 }
1549 
1550 XRRModeInfo *KRandrSimpleAPI::find_mode_by_xid (ScreenInfo *screen_info, RRMode mode_id)
1551 {
1552  return internal_find_mode_by_xid (screen_info, mode_id);
1553 }
1554 
1555 int KRandrSimpleAPI::mode_height (XRRModeInfo *mode_info, Rotation rotation)
1556 {
1557  return internal_mode_height (mode_info, rotation);
1558 }
1559 
1560 int KRandrSimpleAPI::mode_width (XRRModeInfo *mode_info, Rotation rotation)
1561 {
1562  return internal_mode_width (mode_info, rotation);
1563 }
1564 
1565 int KRandrSimpleAPI::get_width_by_output_id (ScreenInfo *screen_info, RROutput output_id)
1566 {
1567  return internal_get_width_by_output_id (screen_info, output_id);
1568 }
1569 
1570 int KRandrSimpleAPI::get_height_by_output_id (ScreenInfo *screen_info, RROutput output_id)
1571 {
1572  return internal_get_height_by_output_id (screen_info, output_id);
1573 }
1574 
1575 char *KRandrSimpleAPI::get_output_name (ScreenInfo *screen_info, RROutput id)
1576 {
1577  return internal_get_output_name (screen_info, id);
1578 }
1579 
1580 Status KRandrSimpleAPI::crtc_apply (CrtcInfo *crtc_info)
1581 {
1582  return internal_crtc_apply (crtc_info);
1583 }
1584 
1585 Status KRandrSimpleAPI::crtc_disable (CrtcInfo *crtc)
1586 {
1587  return internal_crtc_disable (crtc);
1588 }
1589 
1590 int KRandrSimpleAPI::main_low_apply (ScreenInfo *screen_info)
1591 {
1592  return internal_main_low_apply (screen_info);
1593 }
1594 
1595 void KRandrSimpleAPI::set_primary_output (ScreenInfo *screen_info, RROutput output_id)
1596 {
1597  internal_output_set_primary(screen_info, output_id);
1598 }
1599 
1600 bool KRandrSimpleAPI::kRandrHasRandr(void)
1601 {
1602  return isValid();
1603 }
1604 
1605 const char *KRandrSimpleAPI::kRandrVersion(void)
1606 {
1607  return "0.9.5";
1608 }
1609 
1610 const char *KRandrSimpleAPI::kRandrCopyright(void)
1611 {
1612  return "LibKRandr 0.9.5 (C)2010 Timothy Pearson <kb9vqf@pearsoncomputing.net>. U.S.A.";
1613 }
1614 
1615 /* * * * * *
1616 
1617  Under this line (------) there's only a C wrapper for the KRandrSimpleAPI class
1618 
1619 * * * * * */
1620 const char *kRandrVersion(void)
1621 {
1622  return KRandrSimpleAPI::kRandrVersion();
1623 }
1624 
1625 const char *kRandrCopyright(void)
1626 {
1627  return KRandrSimpleAPI::kRandrCopyright();
1628 }
1629 
KSimpleConfig::sync
virtual void sync()
tdelocale.h
TDEConfigBase::groupList
virtual TQStringList groupList() const =0
KSimpleConfig

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tderandr by doxygen 1.8.8
This website is maintained by Timothy Pearson.