doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
PickMonitor.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #include <Carbon/Carbon.h>
31 #include "PickMonitor.h"
32 
33 //====================================================================================
34 // CONSTANTS
35 //====================================================================================
36 
37 #define kMaxMonitors 16
38 
39 //====================================================================================
40 // TYPES
41 //====================================================================================
42 
43 typedef struct
44 {
45  GDHandle device;
46  Rect origRect;
47  Rect scaledRect;
48  int isMain;
49 }
50 Monitor;
51 
52 
53 //====================================================================================
54 // GLOBALS
55 //====================================================================================
56 static GDHandle sSelectedDevice;
57 static int sNumMonitors;
58 static Monitor sMonitors[kMaxMonitors];
59 
60 static RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };
61 static RGBColor rgbWhite = { 0xffff, 0xffff, 0xffff };
62 static RGBColor rgbGray = { 0x5252, 0x8A8A, 0xCCCC }; // this is the blue used in the Displays control panel
63 
64 //====================================================================================
65 // MACROS
66 //====================================================================================
67 
68 #undef PtInRect
69 #undef OffsetRect
70 #undef InsetRect
71 #undef EraseRect
72 #undef MoveTo
73 #undef LineTo
74 
75 
76 //====================================================================================
77 // IMPLEMENTATION
78 //====================================================================================
79 
80 //-----------------------------------------------------------------------------
81 // SetupUserPaneProcs
82 //-----------------------------------------------------------------------------
83 // Call this to initialize the specified user pane control before displaying
84 // the dialog window. Pass NULL for any user pane procs you don't need to install.
85 
86 OSErr SetupUserPaneProcs( ControlRef inUserPane,
87  ControlUserPaneDrawProcPtr inDrawProc,
88  ControlUserPaneHitTestProcPtr inHitTestProc,
89  ControlUserPaneTrackingProcPtr inTrackingProc)
90 {
91  OSErr err = noErr;
92  ControlUserPaneDrawUPP drawUPP;
93  ControlUserPaneHitTestUPP hitTestUPP;
94  ControlUserPaneTrackingUPP trackingUPP;
95 
96  if (0 == inUserPane) return paramErr;
97 
98  if (inDrawProc && noErr == err)
99  {
100  drawUPP = NewControlUserPaneDrawUPP(inDrawProc);
101 
102  if (0 == drawUPP)
103  err = memFullErr;
104  else
105  err = SetControlData( inUserPane,
106  kControlEntireControl,
107  kControlUserPaneDrawProcTag,
108  sizeof(ControlUserPaneDrawUPP),
109  (Ptr)&drawUPP);
110  }
111  if (inHitTestProc && noErr == err)
112  {
113  hitTestUPP = NewControlUserPaneHitTestUPP(inHitTestProc);
114 
115  if (0 == hitTestUPP)
116  err = memFullErr;
117  else
118  err = SetControlData( inUserPane,
119  kControlEntireControl,
120  kControlUserPaneHitTestProcTag,
121  sizeof(ControlUserPaneHitTestUPP),
122  (Ptr)&hitTestUPP);
123  }
124  if (inTrackingProc && noErr == err)
125  {
126  trackingUPP = NewControlUserPaneTrackingUPP(inTrackingProc);
127 
128  if (0 == trackingUPP)
129  err = memFullErr;
130  else
131  err = SetControlData( inUserPane,
132  kControlEntireControl,
133  kControlUserPaneTrackingProcTag,
134  sizeof(ControlUserPaneTrackingUPP),
135  (Ptr)&trackingUPP);
136  }
137 
138  return err;
139 }
140 
141 
142 //-----------------------------------------------------------------------------
143 // DisposeUserPaneProcs
144 //-----------------------------------------------------------------------------
145 // Call this to clean up when you're done with the specified user pane control.
146 
147 OSErr DisposeUserPaneProcs(ControlRef inUserPane)
148 {
149  ControlUserPaneDrawUPP drawUPP;
150  ControlUserPaneHitTestUPP hitTestUPP;
151  ControlUserPaneTrackingUPP trackingUPP;
152  Size actualSize;
153  OSErr err;
154 
155  err = GetControlData(inUserPane, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(ControlUserPaneDrawUPP), (Ptr)&drawUPP, &actualSize);
156  if (err == noErr) DisposeControlUserPaneDrawUPP(drawUPP);
157 
158  err = GetControlData(inUserPane, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(ControlUserPaneHitTestUPP), (Ptr)&hitTestUPP, &actualSize);
159  if (err == noErr) DisposeControlUserPaneHitTestUPP(hitTestUPP);
160 
161  err = GetControlData(inUserPane, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(ControlUserPaneTrackingUPP), (Ptr)&trackingUPP, &actualSize);
162  if (err == noErr) DisposeControlUserPaneTrackingUPP(trackingUPP);
163 
164  return noErr;
165 }
166 
167 #pragma mark -
168 
169 //-----------------------------------------------------------------------------
170 // drawProc
171 //-----------------------------------------------------------------------------
172 // Custom drawProc for our UserPane control.
173 
174 static pascal void drawProc(ControlRef inControl, SInt16 inPart)
175 {
176  #pragma unused(inControl, inPart)
177 
178  int i;
179  RGBColor saveForeColor;
180  RGBColor saveBackColor;
181  PenState savePenState;
182 
183  GetForeColor(&saveForeColor);
184  GetBackColor(&saveBackColor);
185  GetPenState(&savePenState);
186 
187  RGBForeColor(&rgbBlack);
188  RGBBackColor(&rgbWhite);
189  PenNormal();
190 
191  for (i = 0; i < sNumMonitors; i++)
192  {
193  RGBForeColor(&rgbGray);
194  PaintRect(&sMonitors[i].scaledRect);
195  if (sMonitors[i].isMain)
196  {
197  Rect r = sMonitors[i].scaledRect;
198  InsetRect(&r, 1, 1);
199  r.bottom = r.top + 6;
200  RGBForeColor(&rgbWhite);
201  PaintRect(&r);
202  RGBForeColor(&rgbBlack);
203  PenSize(1,1);
204  MoveTo(r.left, r.bottom);
205  LineTo(r.right, r.bottom);
206  }
207  if (sMonitors[i].device == sSelectedDevice)
208  {
209  PenSize(3,3);
210  RGBForeColor(&rgbBlack);
211  FrameRect(&sMonitors[i].scaledRect);
212  }
213  else
214  {
215  PenSize(1,1);
216  RGBForeColor(&rgbBlack);
217  FrameRect(&sMonitors[i].scaledRect);
218  }
219  }
220 
221  // restore the original pen state and colors
222  RGBForeColor(&saveForeColor);
223  RGBBackColor(&saveBackColor);
224  SetPenState(&savePenState);
225 }
226 
227 
228 //-----------------------------------------------------------------------------
229 // hitTestProc
230 //-----------------------------------------------------------------------------
231 // Custom hitTestProc for our UserPane control.
232 // This allows FindControlUnderMouse() to locate our control, which allows
233 // ModalDialog() to call TrackControl() or HandleControlClick() for our control.
234 
235 static pascal ControlPartCode hitTestProc(ControlRef inControl, Point inWhere)
236 {
237  // return a valid part code so HandleControlClick() will be called
238  return kControlButtonPart;
239 }
240 
241 
242 //-----------------------------------------------------------------------------
243 // trackingProc
244 //-----------------------------------------------------------------------------
245 // Custom trackingProc for our UserPane control.
246 // This won't be called for our control unless the kControlHandlesTracking feature
247 // bit is specified when the userPane is created.
248 
249 static pascal ControlPartCode trackingProc (
250  ControlRef inControl,
251  Point inStartPt,
252  ControlActionUPP inActionProc)
253 {
254  #pragma unused (inControl, inStartPt, inActionProc)
255  int i;
256 
257  for (i = 0; i < sNumMonitors; i++)
258  {
259  if (PtInRect(inStartPt, &sMonitors[i].scaledRect))
260  {
261  if (sMonitors[i].device != sSelectedDevice)
262  {
263  sSelectedDevice = sMonitors[i].device;
264  DrawOneControl(inControl);
265  }
266  break;
267  }
268  }
269 
270  return kControlNoPart;
271 }
272 
273 
274 #pragma mark -
275 
276 
277 //-----------------------------------------------------------------------------
278 // SetupPickMonitorPane
279 //-----------------------------------------------------------------------------
280 // Call this to initialize the user pane control that is the Pick Monitor
281 // control. Pass the ControlRef of the user pane control and a display ID
282 // for the monitor you want selected by default (pass 0 for the main monitor).
283 // Call this function before displaying the dialog window.
284 
285 OSErr SetupPickMonitorPane(ControlRef inPane, DisplayIDType inDefaultMonitor)
286 {
287  GDHandle dev = GetDeviceList();
288  OSErr err = noErr;
289 
290  // make the default monitor the selected device
291  if (inDefaultMonitor)
292  DMGetGDeviceByDisplayID(inDefaultMonitor, &sSelectedDevice, true);
293  else
294  sSelectedDevice = GetMainDevice();
295 
296  // build the list of monitors
297  sNumMonitors = 0;
298  while (dev && sNumMonitors < kMaxMonitors)
299  {
300  if (TestDeviceAttribute(dev, screenDevice) && TestDeviceAttribute(dev, screenActive))
301  {
302  sMonitors[sNumMonitors].device = dev;
303  sMonitors[sNumMonitors].origRect = (**dev).gdRect;
304  sMonitors[sNumMonitors].isMain = (dev == GetMainDevice());
305  sNumMonitors++;
306  }
307  dev = GetNextDevice(dev);
308  }
309 
310  // calculate scaled rects
311  if (sNumMonitors)
312  {
313  Rect origPaneRect, paneRect;
314  Rect origGrayRect, grayRect, scaledGrayRect;
315  float srcAspect, dstAspect, scale;
316  int i;
317 
318  GetControlBounds(inPane, &origPaneRect);
319  paneRect = origPaneRect;
320  OffsetRect(&paneRect, -paneRect.left, -paneRect.top);
321 
322  GetRegionBounds(GetGrayRgn(), &origGrayRect);
323  grayRect = origGrayRect;
324  OffsetRect(&grayRect, -grayRect.left, -grayRect.top);
325 
326  srcAspect = (float)grayRect.right / (float)grayRect.bottom;
327  dstAspect = (float)paneRect.right / (float)paneRect.bottom;
328 
329  scaledGrayRect = paneRect;
330 
331  if (srcAspect < dstAspect)
332  {
333  scaledGrayRect.right = (float)paneRect.bottom * srcAspect;
334  scale = (float)scaledGrayRect.right / grayRect.right;
335  }
336  else
337  {
338  scaledGrayRect.bottom = (float)paneRect.right / srcAspect;
339  scale = (float)scaledGrayRect.bottom / grayRect.bottom;
340  }
341 
342  for (i = 0; i < sNumMonitors; i++)
343  {
344  Rect r = sMonitors[i].origRect;
345  Rect r2 = r;
346 
347  // normalize rect and scale
348  OffsetRect(&r, -r.left, -r.top);
349  r.bottom = (float)r.bottom * scale;
350  r.right = (float)r.right * scale;
351 
352  // offset rect wrt gray region
353  OffsetRect(&r, (float)(r2.left - origGrayRect.left) * scale,
354  (float)(r2.top - origGrayRect.top) * scale);
355 
356  sMonitors[i].scaledRect = r;
357  }
358 
359  // center scaledGrayRect in the pane
360  OffsetRect(&scaledGrayRect, (paneRect.right - scaledGrayRect.right) / 2,
361  (paneRect.bottom - scaledGrayRect.bottom) / 2);
362 
363  // offset monitors to match
364  for (i = 0; i < sNumMonitors; i++)
365  OffsetRect(&sMonitors[i].scaledRect, scaledGrayRect.left, scaledGrayRect.top);
366  }
367  else
368  return paramErr;
369 
370  // setup the procs for the pick monitor user pane
371  err = SetupUserPaneProcs(inPane, drawProc, hitTestProc, trackingProc);
372  return err;
373 }
374 
375 
376 //-----------------------------------------------------------------------------
377 // TearDownPickMonitorPane
378 //-----------------------------------------------------------------------------
379 // Disposes of everything associated with the Pick Monitor pane. You should
380 // call this when disposing the dialog.
381 
382 OSErr TearDownPickMonitorPane(ControlRef inPane)
383 {
384  OSErr err;
385  err = DisposeUserPaneProcs(inPane);
386  sNumMonitors = 0;
387  return err;
388 }
389 
390 #pragma mark -
391 
392 //------------------------------------------------------------------------------------
393 // ¥ PickMonitorHandler
394 //------------------------------------------------------------------------------------
395 // Our command handler for the PickMonitor dialog.
396 
397 static pascal OSStatus PickMonitorHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* inUserData )
398 {
399  #pragma unused( inHandler )
400 
401  HICommand cmd;
402  OSStatus result = eventNotHandledErr;
403  WindowRef theWindow = (WindowRef)inUserData;
404 
405  // The direct object for a 'process commmand' event is the HICommand.
406  // Extract it here and switch off the command ID.
407 
408  GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof( cmd ), NULL, &cmd );
409 
410  switch ( cmd.commandID )
411  {
412  case kHICommandOK:
413  QuitAppModalLoopForWindow( theWindow );
414  result = noErr;
415  break;
416 
417  case kHICommandCancel:
418  // Setting sSelectedDevice to zero will signal that the user cancelled.
419  sSelectedDevice = 0;
420  QuitAppModalLoopForWindow( theWindow );
421  result = noErr;
422  break;
423 
424  }
425  return result;
426 }
427 
428 
429 #pragma mark -
430 
431 //-----------------------------------------------------------------------------
432 // CanUserPickMonitor
433 //-----------------------------------------------------------------------------
434 // Returns true if more than one monitor is available to choose from.
435 
436 Boolean CanUserPickMonitor (void)
437 {
438  GDHandle dev = GetDeviceList();
439  OSErr err = noErr;
440  int numMonitors;
441 
442  // build the list of monitors
443  numMonitors = 0;
444  while (dev && numMonitors < kMaxMonitors)
445  {
446  if (TestDeviceAttribute(dev, screenDevice) && TestDeviceAttribute(dev, screenActive))
447  {
448  numMonitors++;
449  }
450  dev = GetNextDevice(dev);
451  }
452 
453  if (numMonitors > 1) return true;
454  else return false;
455 }
456 
457 //-----------------------------------------------------------------------------
458 // PickMonitor
459 //-----------------------------------------------------------------------------
460 // Prompts for a monitor. Returns userCanceledErr if the user cancelled.
461 
462 OSStatus PickMonitor (DisplayIDType *inOutDisplayID, WindowRef parentWindow)
463 {
464  WindowRef theWindow;
465  OSStatus status = noErr;
466  static const ControlID kUserPane = { 'MONI', 1 };
467 
468  // Fetch the dialog
469 
470  IBNibRef aslNib;
471  CFBundleRef theBundle = CFBundleGetMainBundle();
472  status = CreateNibReferenceWithCFBundle(theBundle, CFSTR("ASLCore"), &aslNib);
473  status = ::CreateWindowFromNib(aslNib, CFSTR( "Pick Monitor" ), &theWindow );
474  if (status != noErr)
475  {
476  assert(false);
477  return userCanceledErr;
478  }
479 
480 #if 0
481  // Put game name in window title. By default the title includes the token <<<kGameName>>>.
482 
483  Str255 windowTitle;
484  GetWTitle(theWindow, windowTitle);
485  FormatPStringWithGameName(windowTitle);
486  SetWTitle(theWindow, windowTitle);
487 #endif
488 
489  // Set up the controls
490 
491  ControlRef monitorPane;
492  GetControlByID( theWindow, &kUserPane, &monitorPane );
493  assert(monitorPane);
494 
495  SetupPickMonitorPane(monitorPane, *inOutDisplayID);
496 
497  // Create our UPP and install the handler.
498 
499  EventTypeSpec cmdEvent = { kEventClassCommand, kEventCommandProcess };
500  EventHandlerUPP handler = NewEventHandlerUPP( PickMonitorHandler );
501  InstallWindowEventHandler( theWindow, handler, 1, &cmdEvent, theWindow, NULL );
502 
503  // Show the window
504 
505  if (parentWindow)
506  ShowSheetWindow( theWindow, parentWindow );
507  else
508  ShowWindow( theWindow );
509 
510  // Now we run modally. We will remain here until the PrefHandler
511  // calls QuitAppModalLoopForWindow if the user clicks OK or
512  // Cancel.
513 
514  RunAppModalLoopForWindow( theWindow );
515 
516  // OK, we're done. Dispose of our window and our UPP.
517  // We do the UPP last because DisposeWindow can send out
518  // CarbonEvents, and we haven't explicitly removed our
519  // handler. If we disposed the UPP, the Toolbox might try
520  // to call it. That would be bad.
521 
522  TearDownPickMonitorPane(monitorPane);
523  if (parentWindow)
524  HideSheetWindow( theWindow );
525  DisposeWindow( theWindow );
526  DisposeEventHandlerUPP( handler );
527 
528  // Return settings to caller
529 
530  if (sSelectedDevice != 0)
531  {
532  // Read back the controls
533  DMGetDisplayIDByGDevice (sSelectedDevice, &*inOutDisplayID, true);
534  return noErr;
535  }
536  else
537  return userCanceledErr;
538 
539 }
540 
GetControlByID(prefInfo.window,&kFullscreenBtn,&prefInfo.fullscreenBtn)
OSStatus PickMonitor(DisplayIDType *inOutDisplayID, WindowRef parentWindow)
assert(prefInfo.fullscreenBtn)
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:4804
case const float
Definition: Callbacks.cpp:62
int i
Definition: process.py:33
Boolean result
Rect origRect
Definition: PickMonitor.cpp:46
CFBundleRef theBundle
OSErr TearDownPickMonitorPane(ControlRef inPane)
InstallWindowEventHandler(prefInfo.window, handler, 1,&cmdEvent,&prefInfo, NULL)
#define kMaxMonitors
Definition: PickMonitor.cpp:37
OSErr SetupUserPaneProcs(ControlRef inUserPane, ControlUserPaneDrawProcPtr inDrawProc, ControlUserPaneHitTestProcPtr inHitTestProc, ControlUserPaneTrackingProcPtr inTrackingProc)
Definition: PickMonitor.cpp:86
#define NULL
Definition: Lib.h:88
OSErr DisposeUserPaneProcs(ControlRef inUserPane)
GLdouble GLdouble GLdouble r
Definition: glext.h:2951
EventTypeSpec cmdEvent
static WindowRef ValidModeCallbackProc inCallback OSStatus err
OSErr SetupPickMonitorPane(ControlRef inPane, DisplayIDType inDefaultMonitor)
int isMain
Definition: PickMonitor.cpp:48
Rect scaledRect
Definition: PickMonitor.cpp:47
Boolean CanUserPickMonitor(void)
IBNibRef aslNib
EventHandlerUPP handler
GDHandle device
Definition: PickMonitor.cpp:45