Exemple #1
0
/**
 * Send a D-Bus reply.
 *
 * @param ps current session
 * @param srcmsg original message
 * @param func a function that modifies the built message, to, for example,
 *        add an argument
 * @param data data pointer to pass to the function
 */
static bool
cdbus_reply(session_t *ps, DBusMessage *srcmsg,
    bool (*func)(session_t *ps, DBusMessage *msg, const void *data),
    const void *data) {
  DBusMessage* msg = NULL;

  // Create a reply
  msg = dbus_message_new_method_return(srcmsg);
  if (!msg) {
    printf_errf("(): Failed to create D-Bus reply.");
    return false;
  }

  // Append arguments onto message
  if (func && !func(ps, msg, data)) {
    dbus_message_unref(msg);
    return false;
  }

  // Send the message and flush the connection
  if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
    printf_errf("(): Failed to send D-Bus reply.");
    dbus_message_unref(msg);
    return false;
  }
  dbus_connection_flush(ps->dbus_conn);

  // Free the message
  dbus_message_unref(msg);

  return true;
}
Exemple #2
0
/**
 * Get n-th argument of a D-Bus message.
 *
 * @param count the position of the argument to get, starting from 0
 * @param type libdbus type number of the type
 * @param pdest pointer to the target
 * @return true if successful, false otherwise.
 */
static bool
cdbus_msg_get_arg(DBusMessage *msg, int count, const int type, void *pdest) {
  assert(count >= 0);

  DBusMessageIter iter = { };
  if (!dbus_message_iter_init(msg, &iter)) {
    printf_errf("(): Message has no argument.");
    return false;
  }

  {
    const int oldcount = count;
    while (count) {
      if (!dbus_message_iter_next(&iter)) {
        printf_errf("(): Failed to find argument %d.", oldcount);
        return false;
      }
      --count;
    }
  }

  if (type != dbus_message_iter_get_arg_type(&iter)) {
    printf_errf("(): Argument has incorrect type.");
    return false;
  }

  dbus_message_iter_get_basic(&iter, pdest);

  return true;
}
Exemple #3
0
/**
 * Send a D-Bus signal.
 *
 * @param ps current session
 * @param name signal name
 * @param func a function that modifies the built message, to, for example,
 *        add an argument
 * @param data data pointer to pass to the function
 */
static bool
cdbus_signal(session_t *ps, const char *name,
    bool (*func)(session_t *ps, DBusMessage *msg, const void *data),
    const void *data) {
  DBusMessage* msg = NULL;

  // Create a signal
  msg = dbus_message_new_signal(CDBUS_OBJECT_NAME, CDBUS_INTERFACE_NAME,
      name);
  if (!msg) {
    printf_errf("(): Failed to create D-Bus signal.");
    return false;
  }

  // Append arguments onto message
  if (func && !func(ps, msg, data)) {
    dbus_message_unref(msg);
    return false;
  }

  // Send the message and flush the connection
  if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
    printf_errf("(): Failed to send D-Bus signal.");
    dbus_message_unref(msg);
    return false;
  }
  dbus_connection_flush(ps->dbus_conn);

  // Free the message
  dbus_message_unref(msg);

  return true;
}
Exemple #4
0
/**
 * Process a find_win D-Bus request.
 */
static bool
cdbus_process_find_win(session_t *ps, DBusMessage *msg) {
  const char *target = NULL;

  if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
    return false;

  Window wid = None;

  // Find window by client window
  if (!strcmp("client", target)) {
    cdbus_window_t client = None;
    if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_WINDOW, &client))
      return false;
    win *w = find_toplevel(ps, client);
    if (w)
      wid = w->id;
  }
  // Find focused window
  else if (!strcmp("focused", target)) {
    win *w = find_focused(ps);
    if (w)
      wid = w->id;
  }
  else {
    printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
    cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);

    return true;
  }

  cdbus_reply_wid(ps, msg, wid);

  return true;
}
Exemple #5
0
/**
 * Callback to append a double argument to a message.
 */
static bool
cdbus_apdarg_double(session_t *ps, DBusMessage *msg, const void *data) {
  if (!dbus_message_append_args(msg, DBUS_TYPE_DOUBLE, data,
        DBUS_TYPE_INVALID)) {
    printf_errf("(): Failed to append argument.");
    return false;
  }

  return true;
}
Exemple #6
0
/**
 * Send a D-Bus error reply.
 *
 * @param ps current session
 * @param msg the new error DBusMessage
 */
static bool
cdbus_reply_errm(session_t *ps, DBusMessage *msg) {
  if (!msg) {
    printf_errf("(): Failed to create D-Bus reply.");
    return false;
  }

  // Send the message and flush the connection
  if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
    printf_errf("(): Failed to send D-Bus reply.");
    dbus_message_unref(msg);
    return false;
  }
  dbus_connection_flush(ps->dbus_conn);

  // Free the message
  dbus_message_unref(msg);

  return true;
}
Exemple #7
0
/**
 * Callback to append an cdbus_enum_t argument to a message.
 */
static bool
cdbus_apdarg_enum(session_t *ps, DBusMessage *msg, const void *data) {
  assert(data);
  if (!dbus_message_append_args(msg, CDBUS_TYPE_ENUM, data,
        DBUS_TYPE_INVALID)) {
    printf_errf("(): Failed to append argument.");
    return false;
  }

  return true;
}
Exemple #8
0
/**
 * Callback to append all window IDs to a message.
 */
static bool
cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
  // Get the number of wids we are to include
  unsigned count = 0;
  for (win *w = ps->list; w; w = w->next) {
    if (!w->destroyed)
      ++count;
  }

  // Allocate memory for an array of window IDs
  cdbus_window_t *arr = malloc(sizeof(cdbus_window_t) * count);
  if (!arr) {
    printf_errf("(): Failed to allocate memory for window ID array.");
    return false;
  }

  // Build the array
  {
    cdbus_window_t *pcur = arr;
    for (win *w = ps->list; w; w = w->next) {
      if (!w->destroyed) {
        *pcur = w->id;
        ++pcur;
        assert(pcur <= arr + count);
      }
    }
    assert(pcur == arr + count);
  }

  // Append arguments
  if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, CDBUS_TYPE_WINDOW,
        &arr, count, DBUS_TYPE_INVALID)) {
    printf_errf("(): Failed to append argument.");
    free(arr);
    return false;
  }

  free(arr);
  return true;
}
Exemple #9
0
/**
 * Callback to append a Window argument to a message.
 */
static bool
cdbus_apdarg_wid(session_t *ps, DBusMessage *msg, const void *data) {
  assert(data);
  cdbus_window_t val = *(const Window *)data;

  if (!dbus_message_append_args(msg, CDBUS_TYPE_WINDOW, &val,
        DBUS_TYPE_INVALID)) {
    printf_errf("(): Failed to append argument.");
    return false;
  }

  return true;
}
Exemple #10
0
/**
 * Callback to append a bool argument to a message.
 */
static bool
cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data) {
  assert(data);

  dbus_bool_t val = *(const bool *) data;

  if (!dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &val,
        DBUS_TYPE_INVALID)) {
    printf_errf("(): Failed to append argument.");
    return false;
  }

  return true;
}
Exemple #11
0
/**
 * Callback to append a string argument to a message.
 */
static bool
cdbus_apdarg_string(session_t *ps, DBusMessage *msg, const void *data) {
  const char *str = data;
  if (!str)
    str = "";

  if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &str,
        DBUS_TYPE_INVALID)) {
    printf_errf("(): Failed to append argument.");
    return false;
  }

  return true;
}
Exemple #12
0
/**
 * @brief Create all ancestor directories of given path.
 *
 * @param path input path
 *
 * @return true if successful, false otherwise
 */
bool path_create_ancestors(char *path) {
  char *p = path;
  char *pprev = NULL;
  while ((pprev = p), (p = strchr(p, '/'))) {
    ++p;
    // Ignore if the segment is empty
    if ((p - pprev) <= 1)
      continue;
    char c = *p;
    *p = '\0';
    if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) && EEXIST != errno) {
      printf_errf("(): Failed to create directory %s: %d (%s)", path, errno,
          dumpstr_errno());
      return false;
    }
    *p = c;
  }

  return true;
}
Exemple #13
0
/**
 * Destroy D-Bus connection.
 */
void
cdbus_destroy(session_t *ps) {
  if (ps->dbus_conn) {
    // Release DBus name firstly
    if (ps->dbus_service) {
      DBusError err = { };
      dbus_error_init(&err);

      dbus_bus_release_name(ps->dbus_conn, ps->dbus_service, &err);
      if (dbus_error_is_set(&err)) {
        printf_errf("(): Failed to release DBus name (%s).",
            err.message);
        dbus_error_free(&err);
      }
    }

    // Close and unref the connection
    dbus_connection_close(ps->dbus_conn);
    dbus_connection_unref(ps->dbus_conn);
  }
}
Exemple #14
0
/**
 * Process a opts_set D-Bus request.
 */
static bool
cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
  const char *target = NULL;

  if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
    return false;

#define cdbus_m_opts_set_do(tgt, type, real_type) \
  if (!strcmp(MSTR(tgt), target)) { \
    real_type val; \
    if (!cdbus_msg_get_arg(msg, 1, type, &val)) \
      return false; \
    ps->o.tgt = val; \
    goto cdbus_process_opts_set_success; \
  }

  // unredir_if_possible
  if (!strcmp("unredir_if_possible", target)) {
    dbus_bool_t val = FALSE;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
      return false;
    if (ps->o.unredir_if_possible != val) {
      ps->o.unredir_if_possible = val;
      ps->ev_received = true;
    }
    goto cdbus_process_opts_set_success;
  }

  // track_focus
  if (!strcmp("track_focus", target)) {
    dbus_bool_t val = FALSE;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
      return false;
    // You could enable this option, but never turn if off
    if (val) {
      opts_init_track_focus(ps);
    }
    goto cdbus_process_opts_set_success;
  }

  // vsync
  if (!strcmp("vsync", target)) {
    const char * val = NULL;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_STRING, &val))
      return false;
    if (!parse_vsync(ps, val)) {
      printf_errf("(): " CDBUS_ERROR_BADARG_S, 1, "Value invalid.");
      cdbus_reply_err(ps, msg, CDBUS_ERROR_BADARG, CDBUS_ERROR_BADARG_S, 1, "Value invalid.");
    }
    else if (!vsync_init(ps)) {
      printf_errf("(): " CDBUS_ERROR_CUSTOM_S, "Failed to initialize specified VSync method.");
      cdbus_reply_err(ps, msg, CDBUS_ERROR_CUSTOM, CDBUS_ERROR_CUSTOM_S, "Failed to initialize specified VSync method.");
    }
    else
      goto cdbus_process_opts_set_success;
    return true;
  }

#undef cdbus_m_opts_set_do

  printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
  cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);

  return true;

cdbus_process_opts_set_success:
  if (!dbus_message_get_no_reply(msg))
    cdbus_reply_bool(ps, msg, true);
  return true;
}
Exemple #15
0
/**
 * Process a opts_get D-Bus request.
 */
static bool
cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
  const char *target = NULL;

  if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
    return false;

#define cdbus_m_opts_get_do(tgt, apdarg_func) \
  if (!strcmp(MSTR(tgt), target)) { \
    apdarg_func(ps, msg, ps->o.tgt); \
    return true; \
  }

  // display
  if (!strcmp("display", target)) {
    cdbus_reply_string(ps, msg, DisplayString(ps->dpy));
    return true;
  }

  cdbus_m_opts_get_do(config_file, cdbus_reply_string);
  cdbus_m_opts_get_do(mark_wmwin_focused, cdbus_reply_bool);
  cdbus_m_opts_get_do(mark_ovredir_focused, cdbus_reply_bool);
  cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
  cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool);
  cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool);
  cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
  cdbus_m_opts_get_do(logpath, cdbus_reply_string);
  cdbus_m_opts_get_do(synchronize, cdbus_reply_bool);

  cdbus_m_opts_get_do(refresh_rate, cdbus_reply_int32);
  cdbus_m_opts_get_do(sw_opti, cdbus_reply_bool);
  if (!strcmp("vsync", target)) {
    assert(ps->o.vsync < sizeof(VSYNC_STRS) / sizeof(VSYNC_STRS[0]));
    cdbus_reply_string(ps, msg, VSYNC_STRS[ps->o.vsync]);
    return true;
  }
  if (!strcmp("backend", target)) {
    assert(ps->o.backend < sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0]));
    cdbus_reply_string(ps, msg, BACKEND_STRS[ps->o.backend]);
    return true;
  }
  cdbus_m_opts_get_do(dbe, cdbus_reply_bool);
  cdbus_m_opts_get_do(vsync_aggressive, cdbus_reply_bool);

  cdbus_m_opts_get_do(blur_background, cdbus_reply_bool);
  cdbus_m_opts_get_do(blur_background_frame, cdbus_reply_bool);
  cdbus_m_opts_get_do(blur_background_fixed, cdbus_reply_bool);

  cdbus_m_opts_get_do(inactive_dim, cdbus_reply_double);
  cdbus_m_opts_get_do(inactive_dim_fixed, cdbus_reply_bool);

  cdbus_m_opts_get_do(use_ewmh_active_win, cdbus_reply_bool);
  cdbus_m_opts_get_do(detect_transient, cdbus_reply_bool);
  cdbus_m_opts_get_do(detect_client_leader, cdbus_reply_bool);

#ifdef CONFIG_VSYNC_OPENGL
  cdbus_m_opts_get_do(glx_no_stencil, cdbus_reply_bool);
  cdbus_m_opts_get_do(glx_copy_from_front, cdbus_reply_bool);
  cdbus_m_opts_get_do(glx_use_copysubbuffermesa, cdbus_reply_bool);
  cdbus_m_opts_get_do(glx_no_rebind_pixmap, cdbus_reply_bool);
  cdbus_m_opts_get_do(glx_swap_method, cdbus_reply_int32);
#endif

  cdbus_m_opts_get_do(track_focus, cdbus_reply_bool);
  cdbus_m_opts_get_do(track_wdata, cdbus_reply_bool);
  cdbus_m_opts_get_do(track_leader, cdbus_reply_bool);
#undef cdbus_m_opts_get_do

  printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
  cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);

  return true;
}
Exemple #16
0
/**
 * Process a opts_set D-Bus request.
 */
static bool
cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
  const char *target = NULL;

  if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
    return false;

#define cdbus_m_opts_set_do(tgt, type, real_type) \
  if (!strcmp(MSTR(tgt), target)) { \
    real_type val; \
    if (!cdbus_msg_get_arg(msg, 1, type, &val)) \
      return false; \
    ps->o.tgt = val; \
    goto cdbus_process_opts_set_success; \
  }

  // fade_delta
  if (!strcmp("fade_delta", target)) {
    int32_t val = 0.0;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_INT32, &val))
      return false;
    ps->o.fade_delta = max_i(val, 1);
    goto cdbus_process_opts_set_success;
  }

  // fade_in_step
  if (!strcmp("fade_in_step", target)) {
    double val = 0.0;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
      return false;
    ps->o.fade_in_step = normalize_d(val) * OPAQUE;
    goto cdbus_process_opts_set_success;
  }

  // fade_out_step
  if (!strcmp("fade_out_step", target)) {
    double val = 0.0;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
      return false;
    ps->o.fade_out_step = normalize_d(val) * OPAQUE;
    goto cdbus_process_opts_set_success;
  }

  // no_fading_openclose
  if (!strcmp("no_fading_openclose", target)) {
    dbus_bool_t val = FALSE;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
      return false;
    opts_set_no_fading_openclose(ps, val);
    goto cdbus_process_opts_set_success;
  }

  // unredir_if_possible
  if (!strcmp("unredir_if_possible", target)) {
    dbus_bool_t val = FALSE;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
      return false;
    if (ps->o.unredir_if_possible != val) {
      ps->o.unredir_if_possible = val;
      ps->ev_received = true;
    }
    goto cdbus_process_opts_set_success;
  }

  // clear_shadow
  if (!strcmp("clear_shadow", target)) {
    dbus_bool_t val = FALSE;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
      return false;
    if (ps->o.clear_shadow != val) {
      ps->o.clear_shadow = val;
      force_repaint(ps);
    }
    goto cdbus_process_opts_set_success;
  }

  // track_focus
  if (!strcmp("track_focus", target)) {
    dbus_bool_t val = FALSE;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
      return false;
    // You could enable this option, but never turn if off
    if (val) {
      opts_init_track_focus(ps);
    }
    goto cdbus_process_opts_set_success;
  }

  // vsync
  if (!strcmp("vsync", target)) {
    const char * val = NULL;
    if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_STRING, &val))
      return false;
    vsync_deinit(ps);
    if (!parse_vsync(ps, val)) {
      printf_errf("(): " CDBUS_ERROR_BADARG_S, 1, "Value invalid.");
      cdbus_reply_err(ps, msg, CDBUS_ERROR_BADARG, CDBUS_ERROR_BADARG_S, 1, "Value invalid.");
    }
    else if (!vsync_init(ps)) {
      printf_errf("(): " CDBUS_ERROR_CUSTOM_S, "Failed to initialize specified VSync method.");
      cdbus_reply_err(ps, msg, CDBUS_ERROR_CUSTOM, CDBUS_ERROR_CUSTOM_S, "Failed to initialize specified VSync method.");
    }
    else
      goto cdbus_process_opts_set_success;
    return true;
  }

  // redirected_force
  if (!strcmp("redirected_force", target)) {
    cdbus_enum_t val = UNSET;
    if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_ENUM, &val))
      return false;
    ps->o.redirected_force = val;
    force_repaint(ps);
    goto cdbus_process_opts_set_success;
  }

  // stoppaint_force
  cdbus_m_opts_set_do(stoppaint_force, CDBUS_TYPE_ENUM, cdbus_enum_t);

#undef cdbus_m_opts_set_do

  printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
  cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);

  return true;

cdbus_process_opts_set_success:
  if (!dbus_message_get_no_reply(msg))
    cdbus_reply_bool(ps, msg, true);
  return true;
}
Exemple #17
0
/**
 * Process a win_set D-Bus request.
 */
static bool
cdbus_process_win_set(session_t *ps, DBusMessage *msg) {
  cdbus_window_t wid = None;
  const char *target = NULL;
  DBusError err = { };

  if (!dbus_message_get_args(msg, &err,
        CDBUS_TYPE_WINDOW, &wid,
        DBUS_TYPE_STRING, &target,
        DBUS_TYPE_INVALID)) {
    printf_errf("(): Failed to parse argument of \"win_set\" (%s).",
        err.message);
    dbus_error_free(&err);
    return false;
  }

  win *w = find_win(ps, wid);

  if (!w) {
    printf_errf("(): Window %#010x not found.", wid);
    cdbus_reply_err(ps, msg, CDBUS_ERROR_BADWIN, CDBUS_ERROR_BADWIN_S, wid);
    return true;
  }

  ps->ev_received = true;

#define cdbus_m_win_set_do(tgt, type, real_type) \
  if (!strcmp(MSTR(tgt), target)) { \
    real_type val; \
    if (!cdbus_msg_get_arg(msg, 2, type, &val)) \
      return false; \
    w->tgt = val; \
    goto cdbus_process_win_set_success; \
  }

  if (!strcmp("focused_force", target)) {
    cdbus_enum_t val = UNSET;
    if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
      return false;
    win_set_focused_force(ps, w, val);
    goto cdbus_process_win_set_success;
  }

  if (!strcmp("invert_color_force", target)) {
    cdbus_enum_t val = UNSET;
    if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
      return false;
    win_set_invert_color_force(ps, w, val);
    goto cdbus_process_win_set_success;
  }
#undef cdbus_m_win_set_do

  printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
  cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);

  return true;

cdbus_process_win_set_success:
  if (!dbus_message_get_no_reply(msg))
    cdbus_reply_bool(ps, msg, true);
  return true;
}
Exemple #18
0
/**
 * Process a win_get D-Bus request.
 */
static bool
cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
  cdbus_window_t wid = None;
  const char *target = NULL;
  DBusError err = { };

  if (!dbus_message_get_args(msg, &err,
        CDBUS_TYPE_WINDOW, &wid,
        DBUS_TYPE_STRING, &target,
        DBUS_TYPE_INVALID)) {
    printf_errf("(): Failed to parse argument of \"win_get\" (%s).",
        err.message);
    dbus_error_free(&err);
    return false;
  }

  win *w = find_win(ps, wid);

  if (!w) {
    printf_errf("(): Window %#010x not found.", wid);
    cdbus_reply_err(ps, msg, CDBUS_ERROR_BADWIN, CDBUS_ERROR_BADWIN_S, wid);
    return true;
  }

#define cdbus_m_win_get_do(tgt, apdarg_func) \
  if (!strcmp(MSTR(tgt), target)) { \
    apdarg_func(ps, msg, w->tgt); \
    return true; \
  }

  cdbus_m_win_get_do(id, cdbus_reply_wid);

  // next
  if (!strcmp("next", target)) {
    cdbus_reply_wid(ps, msg, (w->next ? w->next->id: 0));
    return true;
  }

  // map_state
  if (!strcmp("map_state", target)) {
    cdbus_reply_bool(ps, msg, w->a.map_state);
    return true;
  }

  cdbus_m_win_get_do(mode, cdbus_reply_enum);
  cdbus_m_win_get_do(client_win, cdbus_reply_wid);
  cdbus_m_win_get_do(damaged, cdbus_reply_bool);
  cdbus_m_win_get_do(destroyed, cdbus_reply_bool);
  cdbus_m_win_get_do(window_type, cdbus_reply_enum);
  cdbus_m_win_get_do(wmwin, cdbus_reply_bool);
  cdbus_m_win_get_do(leader, cdbus_reply_wid);
  cdbus_m_win_get_do(focused_real, cdbus_reply_bool);
  cdbus_m_win_get_do(focused_force, cdbus_reply_enum);
  cdbus_m_win_get_do(invert_color_force, cdbus_reply_enum);
  cdbus_m_win_get_do(name, cdbus_reply_string);
  cdbus_m_win_get_do(class_instance, cdbus_reply_string);
  cdbus_m_win_get_do(class_general, cdbus_reply_string);
  cdbus_m_win_get_do(role, cdbus_reply_string);
  cdbus_m_win_get_do(opacity, cdbus_reply_uint32);
  cdbus_m_win_get_do(frame_opacity, cdbus_reply_double);
  cdbus_m_win_get_do(left_width, cdbus_reply_uint32);
  cdbus_m_win_get_do(right_width, cdbus_reply_uint32);
  cdbus_m_win_get_do(top_width, cdbus_reply_uint32);
  cdbus_m_win_get_do(bottom_width, cdbus_reply_uint32);

  cdbus_m_win_get_do(fade, cdbus_reply_bool);
  cdbus_m_win_get_do(invert_color, cdbus_reply_bool);
  cdbus_m_win_get_do(blur_background, cdbus_reply_bool);
#undef cdbus_m_win_get_do

  printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
  cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);

  return true;
}
Exemple #19
0
/**
 * Process a message from D-Bus.
 */
static void
cdbus_process(session_t *ps, DBusMessage *msg) {
  bool success = false;

#define cdbus_m_ismethod(method) \
  dbus_message_is_method_call(msg, CDBUS_INTERFACE_NAME, method)

  if (cdbus_m_ismethod("reset")) {
    ps->reset = true;
    if (!dbus_message_get_no_reply(msg))
      cdbus_reply_bool(ps, msg, true);
    success = true;
  }
  else if (cdbus_m_ismethod("list_win")) {
    success = cdbus_process_list_win(ps, msg);
  }
  else if (cdbus_m_ismethod("win_get")) {
    success = cdbus_process_win_get(ps, msg);
  }
  else if (cdbus_m_ismethod("win_set")) {
    success = cdbus_process_win_set(ps, msg);
  }
  else if (cdbus_m_ismethod("find_win")) {
    success = cdbus_process_find_win(ps, msg);
  }
  else if (cdbus_m_ismethod("opts_get")) {
    success = cdbus_process_opts_get(ps, msg);
  }
  else if (cdbus_m_ismethod("opts_set")) {
    success = cdbus_process_opts_set(ps, msg);
  }
#undef cdbus_m_ismethod
  else if (dbus_message_is_method_call(msg,
        "org.freedesktop.DBus.Introspectable", "Introspect")) {
    success = cdbus_process_introspect(ps, msg);
  }
  else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired")
      || dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameLost")) {
    success = true;
  }
  else {
    if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) {
      printf_errf("(): Error message of path \"%s\" "
          "interface \"%s\", member \"%s\", error \"%s\"",
          dbus_message_get_path(msg), dbus_message_get_interface(msg),
          dbus_message_get_member(msg), dbus_message_get_error_name(msg));
    }
    else {
      printf_errf("(): Illegal message of type \"%s\", path \"%s\" "
          "interface \"%s\", member \"%s\"",
          cdbus_repr_msgtype(msg), dbus_message_get_path(msg),
          dbus_message_get_interface(msg), dbus_message_get_member(msg));
    }
    if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
        && !dbus_message_get_no_reply(msg))
      cdbus_reply_err(ps, msg, CDBUS_ERROR_BADMSG, CDBUS_ERROR_BADMSG_S);
    success = true;
  }

  // If the message could not be processed, and an reply is expected, return
  // an empty reply.
  if (!success && DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
      && !dbus_message_get_no_reply(msg))
    cdbus_reply_err(ps, msg, CDBUS_ERROR_UNKNOWN, CDBUS_ERROR_UNKNOWN_S);

  // Free the message
  dbus_message_unref(msg);
}
Exemple #20
0
/**
 * Initialize D-Bus connection.
 */
bool
cdbus_init(session_t *ps) {
  DBusError err = { };

  // Initialize
  dbus_error_init(&err);

  // Connect to D-Bus
  // Use dbus_bus_get_private() so we can fully recycle it ourselves
  ps->dbus_conn = dbus_bus_get_private(DBUS_BUS_SESSION, &err);
  if (dbus_error_is_set(&err)) {
    printf_errf("(): D-Bus connection failed (%s).", err.message);
    dbus_error_free(&err);
    return false;
  }

  if (!ps->dbus_conn) {
    printf_errf("(): D-Bus connection failed for unknown reason.");
    return false;
  }

  // Avoid exiting on disconnect
  dbus_connection_set_exit_on_disconnect(ps->dbus_conn, false);

  // Request service name
  {
    // Get display name
    char *display = DisplayString(ps->dpy);
    if (!display)
      display = "unknown";
    display = mstrcpy(display);

    // Convert all special characters in display name to underscore
    {
      char *pdisp = display;

      while (*pdisp) {
        if (!isalnum(*pdisp))
          *pdisp = '_';
        ++pdisp;
      }
    }

    // Build service name
    char *service = mstrjoin3(CDBUS_SERVICE_NAME, ".", display);
    ps->dbus_service = service;

    free(display);
    display = NULL;

    // Request for the name
    int ret = dbus_bus_request_name(ps->dbus_conn, service,
        DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);

    if (dbus_error_is_set(&err)) {
      printf_errf("(): Failed to obtain D-Bus name (%s).", err.message);
      dbus_error_free(&err);
    }

    if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret
        && DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER != ret) {
      printf_errf("(): Failed to become the primary owner of requested "
          "D-Bus name (%d).", ret);
    }
  }


  // Add watch handlers
  if (!dbus_connection_set_watch_functions(ps->dbus_conn,
        cdbus_callback_add_watch, cdbus_callback_remove_watch,
        cdbus_callback_watch_toggled, ps, NULL)) {
    printf_errf("(): Failed to add D-Bus watch functions.");
    return false;
  }

  // Add timeout handlers
  if (!dbus_connection_set_timeout_functions(ps->dbus_conn,
        cdbus_callback_add_timeout, cdbus_callback_remove_timeout,
        cdbus_callback_timeout_toggled, ps, NULL)) {
    printf_errf("(): Failed to add D-Bus timeout functions.");
    return false;
  }

  // Add match
  dbus_bus_add_match(ps->dbus_conn,
      "type='method_call',interface='" CDBUS_INTERFACE_NAME "'", &err);
  if (dbus_error_is_set(&err)) {
    printf_errf("(): Failed to add D-Bus match.");
    dbus_error_free(&err);
    return false;
  }

  return true;
}
Exemple #21
0
/**
 * Parse the target part of a rule.
 */
static int
c2_parse_target(session_t *ps, const char *pattern, int offset, c2_ptr_t *presult) {
  // Initialize leaf
  presult->isbranch = false;
  presult->l = malloc(sizeof(c2_l_t));
  if (!presult->l)
    c2_error("Failed to allocate memory for new leaf.");

  c2_l_t * const pleaf = presult->l;
  memcpy(pleaf, &leaf_def, sizeof(c2_l_t));

  // Parse negation marks
  while ('!' == pattern[offset]) {
    pleaf->neg = !pleaf->neg;
    ++offset;
    C2H_SKIP_SPACES();
  }

  // Copy target name out
  unsigned tgtlen = 0;
  for (; pattern[offset]
      && (isalnum(pattern[offset]) || '_' == pattern[offset]); ++offset) {
    ++tgtlen;
  }
  if (!tgtlen)
    c2_error("Empty target.");
  pleaf->tgt = mstrncpy(&pattern[offset - tgtlen], tgtlen);

  // Check for predefined targets
  for (unsigned i = 1; i < sizeof(C2_PREDEFS) / sizeof(C2_PREDEFS[0]); ++i) {
    if (!strcmp(C2_PREDEFS[i].name, pleaf->tgt)) {
      pleaf->predef = i;
      pleaf->type = C2_PREDEFS[i].type;
      pleaf->format = C2_PREDEFS[i].format;
      break;
    }
  }

  // Alias for predefined targets
  if (!pleaf->predef) {
#define TGTFILL(pdefid) \
  (pleaf->predef = pdefid, \
   pleaf->type = C2_PREDEFS[pdefid].type, \
   pleaf->format = C2_PREDEFS[pdefid].format)

  // if (!strcmp("WM_NAME", tgt) || !strcmp("_NET_WM_NAME", tgt))
  //   TGTFILL(C2_L_PNAME);
#undef TGTFILL

    // Alias for custom properties
#define TGTFILL(target, type, format) \
  (pleaf->target = mstrcpy(target), \
   pleaf->type = type, \
   pleaf->format = format)

    // if (!strcmp("SOME_ALIAS"))
    //   TGTFILL("ALIAS_TEXT", C2_L_TSTRING, 32);
#undef TGTFILL
  }

  C2H_SKIP_SPACES();

  // Parse target-on-frame flag
  if ('@' == pattern[offset]) {
    pleaf->tgt_onframe = true;
    ++offset;
    C2H_SKIP_SPACES();
  }

  // Parse index
  if ('[' == pattern[offset]) {
    offset++;

    C2H_SKIP_SPACES();

    int index = -1;
    char *endptr = NULL;

    index = strtol(pattern + offset, &endptr, 0);

    if (!endptr || pattern + offset == endptr)
      c2_error("No index number found after bracket.");

    if (index < 0)
      c2_error("Index number invalid.");

    if (pleaf->predef)
      c2_error("Predefined targets can't have index.");

    pleaf->index = index;
    offset = endptr - pattern;

    C2H_SKIP_SPACES();

    if (']' != pattern[offset])
      c2_error("Index end marker not found.");

    ++offset;

    C2H_SKIP_SPACES();
  }

  // Parse target type and format
  if (':' == pattern[offset]) {
    ++offset;
    C2H_SKIP_SPACES();

    // Look for format
    bool hasformat = false;
    int format = 0;
    {
      char *endptr = NULL;
      format =  strtol(pattern + offset, &endptr, 0);
      assert(endptr);
      if ((hasformat = (endptr && endptr != pattern + offset)))
        offset = endptr - pattern;
      C2H_SKIP_SPACES();
    }

    // Look for type
    enum c2_l_type type = C2_L_TUNDEFINED;
    {
      switch (pattern[offset]) {
        case 'w': type = C2_L_TWINDOW; break;
        case 'd': type = C2_L_TDRAWABLE; break;
        case 'c': type = C2_L_TCARDINAL; break;
        case 's': type = C2_L_TSTRING; break;
        case 'a': type = C2_L_TATOM; break;
        default:  c2_error("Invalid type character.");
      }

      if (type) {
        if (pleaf->predef) {
          printf_errf("(): Warning: Type specified for a default target will be ignored.");
        }
        else {
          if (pleaf->type && type != pleaf->type)
            printf_errf("(): Warning: Default type overridden on target.");
          pleaf->type = type;
        }
      }

      offset++;
      C2H_SKIP_SPACES();
    }

    // Default format
    if (!pleaf->format) {
      switch (pleaf->type) {
        case C2_L_TWINDOW:
        case C2_L_TDRAWABLE:
        case C2_L_TATOM:
          pleaf->format = 32;  break;
        case C2_L_TSTRING:
          pleaf->format = 8;   break;
        default:
          break;
      }
    }

    // Write format
    if (hasformat) {
      if (pleaf->predef)
        printf_errf("(): Warning: Format \"%d\" specified on a default target will be ignored.", format);
      else if (C2_L_TSTRING == pleaf->type)
        printf_errf("(): Warning: Format \"%d\" specified on a string target will be ignored.", format);
      else {
        if (pleaf->format && pleaf->format != format)
          printf_err("Warning: Default format %d overridden on target.",
              pleaf->format);
        pleaf->format = format;
      }
    }
  }

  if (!pleaf->type)
    c2_error("Target type cannot be determined.");

  // if (!pleaf->predef && !pleaf->format && C2_L_TSTRING != pleaf->type)
  //   c2_error("Target format cannot be determined.");

  if (pleaf->format && 8 != pleaf->format
        && 16 != pleaf->format && 32 != pleaf->format)
    c2_error("Invalid format.");

  return offset;
}
Exemple #22
0
/**
 * Do postprocessing on a condition leaf.
 */
static bool
c2_l_postprocess(session_t *ps, c2_l_t *pleaf) {
  // Give a pattern type to a leaf with exists operator, if needed
  if (C2_L_OEXISTS == pleaf->op && !pleaf->ptntype) {
    pleaf->ptntype =
      (C2_L_TSTRING == pleaf->type ? C2_L_PTSTRING: C2_L_PTINT);
  }

  // Get target atom if it's not a predefined one
  if (!pleaf->predef) {
    pleaf->tgtatom = get_atom(ps, pleaf->tgt);
    if (!pleaf->tgtatom)
      c2_error("Failed to get atom for target \"%s\".", pleaf->tgt);
  }

  // Insert target Atom into atom track list
  if (pleaf->tgtatom) {
    bool found = false;
    for (latom_t *platom = ps->track_atom_lst; platom;
        platom = platom->next) {
      if (pleaf->tgtatom == platom->atom) {
        found = true;
        break;
      }
    }
    if (!found) {
      latom_t *pnew = malloc(sizeof(latom_t));
      if (!pnew)
        printf_errfq(1, "(): Failed to allocate memory for new track atom.");
      pnew->next = ps->track_atom_lst;
      pnew->atom = pleaf->tgtatom;
      ps->track_atom_lst = pnew;
    }
  }

  // Enable specific tracking options in compton if needed by the condition
  // TODO: Add track_leader
  if (pleaf->predef) {
    switch (pleaf->predef) {
      case C2_L_PFOCUSED: ps->o.track_focus = true; break;
      case C2_L_PNAME:
      case C2_L_PCLASSG:
      case C2_L_PCLASSI:
      case C2_L_PROLE:    ps->o.track_wdata = true; break;
      default:            break;
    }
  }

  // Warn about lower case characters in target name
  if (!pleaf->predef) {
    for (const char *pc = pleaf->tgt; *pc; ++pc) {
      if (islower(*pc)) {
        printf_errf("(): Warning: Lowercase character in target name \"%s\".", pleaf->tgt);
        break;
      }
    }
  }

  // PCRE patterns
  if (C2_L_PTSTRING == pleaf->ptntype && C2_L_MPCRE == pleaf->match) {
#ifdef CONFIG_REGEX_PCRE
    const char *error = NULL;
    int erroffset = 0;
    int options = 0;

    // Ignore case flag
    if (pleaf->match_ignorecase)
      options |= PCRE_CASELESS;

    // Compile PCRE expression
    pleaf->regex_pcre = pcre_compile(pleaf->ptnstr, options,
        &error, &erroffset, NULL);
    if (!pleaf->regex_pcre)
      c2_error("Pattern \"%s\": PCRE regular expression parsing failed on "
          "offset %d: %s", pleaf->ptnstr, erroffset, error);
#ifdef CONFIG_REGEX_PCRE_JIT
    pleaf->regex_pcre_extra = pcre_study(pleaf->regex_pcre,
        PCRE_STUDY_JIT_COMPILE, &error);
    if (!pleaf->regex_pcre_extra) {
      printf("Pattern \"%s\": PCRE regular expression study failed: %s",
          pleaf->ptnstr, error);
    }
#endif

    // Free the target string
    // free(pleaf->tgt);
    // pleaf->tgt = NULL;
#else
    c2_error("PCRE regular expression support not compiled in.");
#endif
  }

  return true;
}
Exemple #23
0
/**
 * Process a opts_get D-Bus request.
 */
static bool
cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
  const char *target = NULL;

  if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
    return false;

#define cdbus_m_opts_get_do(tgt, apdarg_func) \
  if (!strcmp(MSTR(tgt), target)) { \
    apdarg_func(ps, msg, ps->o.tgt); \
    return true; \
  }

  // display
  if (!strcmp("display", target)) {
    cdbus_reply_string(ps, msg, DisplayString(ps->dpy));
    return true;
  }

  cdbus_m_opts_get_do(config_file, cdbus_reply_string);
  cdbus_m_opts_get_do(mark_wmwin_focused, cdbus_reply_bool);
  cdbus_m_opts_get_do(mark_ovredir_focused, cdbus_reply_bool);
  cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
  cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool);
  cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool);
  cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
  cdbus_m_opts_get_do(logpath, cdbus_reply_string);
  cdbus_m_opts_get_do(synchronize, cdbus_reply_bool);

  cdbus_m_opts_get_do(refresh_rate, cdbus_reply_int32);
  cdbus_m_opts_get_do(sw_opti, cdbus_reply_bool);
  if (!strcmp("vsync", target)) {
    assert(ps->o.vsync < sizeof(VSYNC_STRS) / sizeof(VSYNC_STRS[0]));
    cdbus_reply_string(ps, msg, VSYNC_STRS[ps->o.vsync]);
    return true;
  }
  cdbus_m_opts_get_do(dbe, cdbus_reply_bool);
  cdbus_m_opts_get_do(vsync_aggressive, cdbus_reply_bool);

  cdbus_m_opts_get_do(shadow_red, cdbus_reply_double);
  cdbus_m_opts_get_do(shadow_green, cdbus_reply_double);
  cdbus_m_opts_get_do(shadow_blue, cdbus_reply_double);
  cdbus_m_opts_get_do(shadow_radius, cdbus_reply_int32);
  cdbus_m_opts_get_do(shadow_offset_x, cdbus_reply_int32);
  cdbus_m_opts_get_do(shadow_offset_y, cdbus_reply_int32);
  cdbus_m_opts_get_do(shadow_opacity, cdbus_reply_double);
  cdbus_m_opts_get_do(clear_shadow, cdbus_reply_bool);

  cdbus_m_opts_get_do(blur_background, cdbus_reply_bool);
  cdbus_m_opts_get_do(blur_background_frame, cdbus_reply_bool);
  cdbus_m_opts_get_do(blur_background_fixed, cdbus_reply_bool);

  cdbus_m_opts_get_do(inactive_dim, cdbus_reply_double);
  cdbus_m_opts_get_do(inactive_dim_fixed, cdbus_reply_bool);

  cdbus_m_opts_get_do(use_ewmh_active_win, cdbus_reply_bool);
  cdbus_m_opts_get_do(detect_transient, cdbus_reply_bool);
  cdbus_m_opts_get_do(detect_client_leader, cdbus_reply_bool);

  cdbus_m_opts_get_do(track_focus, cdbus_reply_bool);
  cdbus_m_opts_get_do(track_wdata, cdbus_reply_bool);
  cdbus_m_opts_get_do(track_leader, cdbus_reply_bool);
#undef cdbus_m_opts_get_do

  printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
  cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);

  return true;
}