update Changes with some of the previous commits
[imager-screenshot.git] / scwin32.c
index 2ce2ab2..b091906 100644 (file)
--- a/scwin32.c
+++ b/scwin32.c
@@ -8,9 +8,35 @@
 #define DISPLAY_DEVICE_ACTIVE 1
 #endif
 
-struct moniter_ctx {
+static void
+i_push_win32_errorf(DWORD msg_id, char const *fmt, ...) {
+  va_list args;
+  LPSTR msg;
+  char buf[1000];
+
+  va_start(args, fmt);
+  vsprintf(buf, fmt, args);
+  if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                   NULL,
+                   msg_id,
+                   0, /* LANGID */
+                   (LPSTR)&msg,
+                   0,
+                   NULL)) {
+    strcat(buf, msg);
+    LocalFree(msg);
+  }
+  else {
+    sprintf(buf+strlen(buf), "%#010x", msg_id);
+  }
+  i_push_error(msg_id, buf);
+  va_end(args);
+}
+
+struct monitor_ctx {
   i_img *out;
   i_img_dim orig_x, orig_y;
+  int good;
 };
 
 static int
@@ -47,19 +73,20 @@ display_to_img(HDC dc, i_img *im, const RECT *src, int dest_x, int dest_y) {
     for (y = 0; y < height; ++y) {
       cp = line;
       for (x = 0; x < width; ++x) {
-       cp->rgb.b = *ch_pp++;
-       cp->rgb.g = *ch_pp++;
-       cp->rgb.r = *ch_pp++;
+       cp->rgba.b = *ch_pp++;
+       cp->rgba.g = *ch_pp++;
+       cp->rgba.r = *ch_pp++;
+       cp->rgba.a = 255;
        ch_pp++;
        cp++;
       }
-      i_plin(im, dest_x, width, dest_y + y, line);
+      i_plin(im, dest_x, dest_x+width, dest_y + y, line);
     }
     myfree(line);
     result = 1;
   }
   else {
-    i_push_errorf(0, "GetDIBits() failure %d", (long)GetLastError());
+    i_push_win32_errorf(GetLastError(), "GetDIBits() failure: ");
   }
 
   myfree(di_bits);
@@ -70,6 +97,18 @@ display_to_img(HDC dc, i_img *im, const RECT *src, int dest_x, int dest_y) {
   return result;
 }
 
+static BOOL CALLBACK
+monitor_enum(HMONITOR hmon, HDC dc, LPRECT r, LPARAM lp_ctx) {
+  struct monitor_ctx *ctx = (struct monitor_ctx *)lp_ctx;
+
+  if (!display_to_img(dc, ctx->out, r,
+                     r->left - ctx->orig_x, r->top - ctx->orig_y)) {
+    ctx->good = 0;
+  }
+
+  return ctx->good;
+}
+
 i_img *
 imss_win32(unsigned hwnd_u, int include_decor, int left, int top, 
           int right, int bottom, int display) {
@@ -113,20 +152,57 @@ imss_win32(unsigned hwnd_u, int include_decor, int left, int top,
     }
     else {
       DISPLAY_DEVICE dd;
-      dd.cb = sizeof(dd);
+      int work_display = 0;
+      int primary_display = -1;
+      int real_display = -1;
 
-      if (EnumDisplayDevices(NULL, display, &dd, 0)) {
-       printf("Flags %lx\n", (unsigned long)dd.StateFlags);
-       if (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) {
-         cdc = CreateDC(dd.DeviceName, dd.DeviceName, NULL, NULL);
+      dd.cb = sizeof(dd);
+      /* look for the primary display, we need a simulate a gap to put the
+        primary at 0 */
+      while (work_display < 100
+            && EnumDisplayDevices(NULL, work_display, &dd, 0)) {
+       if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
+         primary_display = work_display;
+         break;
+       }
+       else if (display && display-1 == work_display) {
+         real_display = work_display;
+         break;
        }
-       else {
-         i_push_errorf(0, "Display device %d not active", display);
+       
+       dd.cb = sizeof(dd);
+       ++work_display;
+      }
+
+      if (!work_display && real_display == -1 && primary_display == -1) {
+       /* EnumDisplayDevices() failed for the first call */
+       i_push_win32_errorf(GetLastError(), "Cannot enumerate device %d(0): ", work_display);
+       return NULL;
+      }
+
+      if (primary_display != -1 && display == 0) {
+       real_display = primary_display;
+      }
+      
+      if (real_display == -1) {
+       /* haven't enumerated the display we want yet */
+       /* we're after the primary */
+       real_display = display;
+       dd.cb = sizeof(dd);
+       if (!EnumDisplayDevices(NULL, real_display, &dd, 0)) {
+         i_push_win32_errorf(GetLastError(), "Cannot enumerate device %d(%d): ",
+                       real_display, display);
          return NULL;
        }
       }
-      else {
-       i_push_errorf(0, "Cannot enumerate device %d: %ld", display, (long)GetLastError());
+
+      if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) {
+       i_push_errorf(0, "Display device %d not active", display);
+       return NULL;
+      }
+      cdc = CreateDC(dd.DeviceName, dd.DeviceName, NULL, NULL);
+      if (!cdc) {
+       i_push_win32_errorf(GetLastError(), "Cannot CreateDC(%s): ", dd.DeviceName);
        return NULL;
       }
 
@@ -178,17 +254,32 @@ imss_win32(unsigned hwnd_u, int include_decor, int left, int top,
     r.right = r.left + width;
     r.bottom = r.top + height;
     
-    if (display_to_img(wdc, result, &r, 0, 0)) {
+    if (display == -1) {
+      struct monitor_ctx ctx;
+      ctx.out = result;
+      ctx.orig_x = orig_x;
+      ctx.orig_y = orig_y;
+      ctx.good = 1;
+
+      if (!EnumDisplayMonitors(wdc, &r, monitor_enum, (LPARAM)&ctx)
+         || !ctx.good) {
+       i_img_destroy(result);
+       result = NULL;
+      }
+    }
+    else {
+      if (!display_to_img(wdc, result, &r, 0, 0)) {
+       i_img_destroy(result);
+       result = NULL;
+      }
+    }
+    if (result) {
       i_tags_setn(&result->tags, "ss_window_width", window_width);
       i_tags_setn(&result->tags, "ss_window_height", window_height);
       i_tags_set(&result->tags, "ss_type", "Win32", 5);
       i_tags_setn(&result->tags, "ss_left", left);
       i_tags_setn(&result->tags, "ss_top", top);
     }
-    else {
-      i_img_destroy(result);
-      result = NULL;
-    }
   }
   /* clean up */
   if (cdc) {